|
| 1 | +import { Tab, Tabs } from "rspress/theme"; |
| 2 | + |
| 3 | +# Agents |
| 4 | + |
| 5 | +Agents in AIScript provide a powerful way to create autonomous, goal-directed AI assistants with access to specific tools and capabilities. The `agent` keyword allows you to define intelligent agents that can execute complex workflows, make decisions, and interact with both users and other agents. |
| 6 | + |
| 7 | +## Basic Syntax |
| 8 | + |
| 9 | +An agent is defined using the `agent` keyword followed by a name and a set of configurations and tool functions: |
| 10 | + |
| 11 | +```rust |
| 12 | +agent AgentName { |
| 13 | + instructions: "Detailed instructions for the agent", |
| 14 | + model: "model-name", // Optional |
| 15 | + tools: [function1, function2], // Optional |
| 16 | + fn tool_function1(param1: type, param2: type) -> return_type { |
| 17 | + // Tool implementation |
| 18 | + } |
| 19 | + fn tool_function2(param: type) -> return_type { |
| 20 | + // Another tool implementation |
| 21 | + } |
| 22 | +} |
| 23 | +``` |
| 24 | + |
| 25 | +## Agent Configuration |
| 26 | + |
| 27 | +Agents can be configured with several parameters: |
| 28 | + |
| 29 | +| Parameter | Type | Description | |
| 30 | +|-----------|------|-------------| |
| 31 | +| `instructions` | String | Detailed instructions for the agent's behavior and goals | |
| 32 | +| `model` | String | Optional. The LLM model to use (defaults to system default) | |
| 33 | +| `tools` | Array | Optional. List of external functions the agent can use | |
| 34 | +| `tool_choice` | String | Optional. Strategy for selecting tools ("auto" or "none") | |
| 35 | + |
| 36 | +## Agent Tools |
| 37 | + |
| 38 | +Tools are functions that agents can call to perform specific actions. Tools can be defined in three ways: |
| 39 | + |
| 40 | +1. **Internal tools**: Functions defined inside the agent block |
| 41 | +2. **External tools**: Functions passed to the agent via the `tools` parameter |
| 42 | +3. **Tool references**: References to tools defined in other files or modules |
| 43 | + |
| 44 | +Example of internal tools: |
| 45 | + |
| 46 | +```rust |
| 47 | +agent Researcher { |
| 48 | + instructions: "You are a research assistant...", |
| 49 | + |
| 50 | + fn search_web(query: str) -> str { |
| 51 | + // Implementation |
| 52 | + return "search results"; |
| 53 | + } |
| 54 | + |
| 55 | + fn save_notes(content: str) -> bool { |
| 56 | + // Implementation |
| 57 | + return true; |
| 58 | + } |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +Example of external tools: |
| 63 | + |
| 64 | +```rust |
| 65 | +fn fetch_data(url: str) -> str { |
| 66 | + // Implementation |
| 67 | +} |
| 68 | + |
| 69 | +fn analyze_data(data: str) -> object { |
| 70 | + // Implementation |
| 71 | +} |
| 72 | + |
| 73 | +agent DataAnalyst { |
| 74 | + instructions: "You are a data analyst...", |
| 75 | + tools: [fetch_data, analyze_data] |
| 76 | +} |
| 77 | +``` |
| 78 | + |
| 79 | +### Tool Docs |
| 80 | + |
| 81 | +In order to help LLM understand the purpose of each tool, you can add docstrings to your tools. Docstrings should be placed immediately after the tool's definition and should follow the python-style doc comment format. |
| 82 | + |
| 83 | +```rust |
| 84 | +agent Researcher { |
| 85 | + instructions: "You are a research assistant...", |
| 86 | + |
| 87 | + fn search_web(query: str) -> str { |
| 88 | + """ |
| 89 | + Search the web for information about a topic. |
| 90 | + """ |
| 91 | + // Implementation |
| 92 | + return "search results"; |
| 93 | + } |
| 94 | + |
| 95 | + fn save_notes(content: str) -> bool { |
| 96 | + """ |
| 97 | + Save notes about a topic. |
| 98 | + """ |
| 99 | + // Implementation |
| 100 | + return true; |
| 101 | + } |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +## Running Agents |
| 106 | + |
| 107 | +To activate an agent, use the `run` method. This starts the agent's execution with optional input and configuration: |
| 108 | + |
| 109 | +```rust |
| 110 | +// Basic usage |
| 111 | +let result = MyAgent.run(input="Please help me with this task"); |
| 112 | + |
| 113 | +// With debug mode |
| 114 | +let debug_result = MyAgent.run( |
| 115 | + input="Analyze this data", |
| 116 | + debug=true |
| 117 | +); |
| 118 | +``` |
| 119 | + |
| 120 | +The `run` method accepts these parameters: |
| 121 | + |
| 122 | +| Parameter | Type | Description | |
| 123 | +|-----------|------|-------------| |
| 124 | +| `input` | String | Initial input/instruction for the agent | |
| 125 | +| `debug` | Boolean | Optional. When true, shows detailed agent thought process | |
| 126 | + |
| 127 | +## Multi-Agent Orchestration |
| 128 | + |
| 129 | +AIScript supports sophisticated multi-agent systems where agents can collaborate and transfer control between each other. This enables complex workflows and agent swarms. |
| 130 | + |
| 131 | +:::info |
| 132 | +AIScript builtin multi-agent orchestration was inspired by [OpenAI Swarm](https://github.com/openai/swarm). |
| 133 | +::: |
| 134 | + |
| 135 | +### Agent Transfer |
| 136 | + |
| 137 | +Agents can transfer control to other agents using return values: |
| 138 | + |
| 139 | +```rust |
| 140 | +agent Coordinator { |
| 141 | + instructions: "You coordinate the workflow...", |
| 142 | + |
| 143 | + fn transfer_to_specialist(topic: str) { |
| 144 | + if topic == "finance" { |
| 145 | + return FinanceSpecialist; |
| 146 | + } else { |
| 147 | + return TechSpecialist; |
| 148 | + } |
| 149 | + } |
| 150 | +} |
| 151 | + |
| 152 | +agent FinanceSpecialist { |
| 153 | + instructions: "You provide financial advice...", |
| 154 | + |
| 155 | + fn transfer_back() { |
| 156 | + return Coordinator; |
| 157 | + } |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +## Example: Rock Paper Scissors Game |
| 162 | + |
| 163 | +This example demonstrates a multi-agent system that implements a simple Rock Paper Scissors game: |
| 164 | + |
| 165 | +<Tabs> |
| 166 | +<Tab label="judger.ai"> |
| 167 | + |
| 168 | +```rust |
| 169 | +let player1_move = nil; |
| 170 | +let player2_move = nil; |
| 171 | + |
| 172 | +agent Judge { |
| 173 | + instructions: "You are the judge of the Rock Paper Scissors game. |
| 174 | + 1. Let Player1 move first then Player2 |
| 175 | + 2. Use record_move to store each player's move after it finished |
| 176 | + 3. After both players finished, use announce_result to display the result |
| 177 | + 4. End the game after announcing results", |
| 178 | + |
| 179 | + fn record_move(player: str, move: str) { |
| 180 | + """Record a player's move.""" |
| 181 | + print(player, "choose", move); |
| 182 | + if player == "Player1" { |
| 183 | + player1_move = move; |
| 184 | + } else { |
| 185 | + player2_move = move; |
| 186 | + } |
| 187 | + } |
| 188 | + |
| 189 | + fn announce_result() { |
| 190 | + """Check the recorded moves and announce the winner.""" |
| 191 | + let winning_moves = {"rock": "scissors", "scissors": "paper", "paper": "rock"}; |
| 192 | + if player1_move == player2_move { |
| 193 | + print("It's a tie!"); |
| 194 | + } else if winning_moves[player1_move] == player2_move { |
| 195 | + print("Player 1 wins!"); |
| 196 | + } else { |
| 197 | + print("Player 2 wins!"); |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + fn transfer_to_player1() { |
| 202 | + """Transfer control to Player 1 Agent""" |
| 203 | + return Player1; |
| 204 | + } |
| 205 | + |
| 206 | + fn transfer_to_player2() { |
| 207 | + """Transfer control to Player 2 Agent""" |
| 208 | + return Player2; |
| 209 | + } |
| 210 | +} |
| 211 | +``` |
| 212 | +</Tab> |
| 213 | + |
| 214 | +<Tab label="player.ai"> |
| 215 | + |
| 216 | +```rust |
| 217 | +use std.random; |
| 218 | + |
| 219 | +fn make_move() -> str { |
| 220 | + """Make a move in the game. Returns rock, paper, or scissors.""" |
| 221 | + return random.choice(["rock", "paper", "scissors"]); |
| 222 | +} |
| 223 | + |
| 224 | +fn transfer_to_judge() { |
| 225 | + """Transfer control to Judge Agent""" |
| 226 | + return Judge; |
| 227 | +} |
| 228 | + |
| 229 | +agent Player1 { |
| 230 | + instructions: "You are Player 1 in the Rock Paper Scissors game. |
| 231 | + 1. Make your move using the make_move function |
| 232 | + 2. Transfer control to the judge after your move", |
| 233 | + tools: [make_move, transfer_to_judge], |
| 234 | +} |
| 235 | + |
| 236 | +agent Player2 { |
| 237 | + instructions: "You are Player 2 in the Rock Paper Scissors game. |
| 238 | + 1. Make your move using the make_move function |
| 239 | + 2. Transfer control to the judge after your move", |
| 240 | + tools: [make_move, transfer_to_judge], |
| 241 | +} |
| 242 | +``` |
| 243 | + |
| 244 | +</Tab> |
| 245 | +<Tab label="main.ai"> |
| 246 | + |
| 247 | +```js |
| 248 | +// Start the game with the Judge agent |
| 249 | +Judge.run(input="Let's start play the game!", debug=true); |
| 250 | +// Here are the logs: |
| 251 | +// |
| 252 | +// Judge call transfer_to_player1() |
| 253 | +// Player1 call make_move(): scissors |
| 254 | +// Player1 call transfer_to_judge() |
| 255 | +// Judge call record_move(Player1, scissors) |
| 256 | +// Judge call transfer_to_player2() |
| 257 | +// Player2 call make_move(): paper |
| 258 | +// Player2 call transfer_to_judge() |
| 259 | +// Judge call record_move(Player2, paper) |
| 260 | +// Judge call announce_result(): Player 1 wins! |
| 261 | +``` |
| 262 | + |
| 263 | +</Tab> |
| 264 | +</Tabs> |
| 265 | + |
| 266 | +## Advanced Agent Techniques |
| 267 | + |
| 268 | +### Stateful Agents |
| 269 | + |
| 270 | +Agents can maintain state across interactions by using variables in their surrounding scope: |
| 271 | + |
| 272 | +```rust |
| 273 | +let conversation_history = []; |
| 274 | + |
| 275 | +agent CustomerSupport { |
| 276 | + instructions: "You are a customer support agent...", |
| 277 | + |
| 278 | + fn add_to_history(message: str) { |
| 279 | + conversation_history.push(message); |
| 280 | + } |
| 281 | + |
| 282 | + fn summarize_conversation() -> str { |
| 283 | + let history = conversation_history.join("\n"); |
| 284 | + return prompt "Summarize this conversation: {history}"; |
| 285 | + } |
| 286 | +} |
| 287 | +``` |
| 288 | + |
| 289 | +### Agent Specialization |
| 290 | + |
| 291 | +Create specialized agents for different domains or tasks: |
| 292 | + |
| 293 | +```rust |
| 294 | +agent CodeExpert { |
| 295 | + instructions: "You are an expert in software development...", |
| 296 | + model: "gpt-4", // More capable model for coding tasks |
| 297 | + |
| 298 | + fn review_code(code: str) -> str { |
| 299 | + return prompt "Review this code and provide feedback: {code}"; |
| 300 | + } |
| 301 | +} |
| 302 | + |
| 303 | +agent ContentWriter { |
| 304 | + instructions: "You are a creative content writer...", |
| 305 | + model: "claude-3.7", // Different model for creative tasks |
| 306 | + |
| 307 | + fn write_article(topic: str, style: str) -> str { |
| 308 | + return prompt "Write an article about {topic} in {style} style"; |
| 309 | + } |
| 310 | +} |
| 311 | +``` |
| 312 | + |
| 313 | +## Best Practices |
| 314 | + |
| 315 | +1. **Clear Instructions**: Provide detailed, step-by-step instructions to guide your agent's behavior. |
| 316 | + |
| 317 | +2. **Minimize State**: Keep shared state minimal and explicit to avoid confusion. |
| 318 | + |
| 319 | +3. **Tool Documentation**: Add descriptive docstrings to your tools to help the agent understand their purpose. |
| 320 | + |
| 321 | +4. **Error Handling**: Implement error handling in tools to provide informative feedback. |
| 322 | + |
| 323 | +5. **Agent Boundaries**: Clearly define responsibilities for each agent in multi-agent systems. |
| 324 | + |
| 325 | +6. **Test Thoroughly**: Test your agents with various inputs to ensure they behave as expected. |
| 326 | + |
| 327 | +## Limitations |
| 328 | + |
| 329 | +- Agents operate within the constraints of the underlying LLM models |
| 330 | +- Tool execution may have latency due to API calls and network operations |
| 331 | +- Complex multi-agent systems may require careful orchestration to avoid loops or deadlocks |
| 332 | +- Agents cannot maintain state independently of your code; state must be explicitly managed |
| 333 | + |
| 334 | +## Performance Considerations |
| 335 | + |
| 336 | +- Use the most appropriate model for each agent based on task complexity |
| 337 | +- Consider batching operations when possible to reduce API calls |
| 338 | +- Monitor token usage for cost management |
| 339 | +- For complex workflows, consider implementing checkpoints or resumable states |
| 340 | + |
| 341 | +Agents in AIScript provide a powerful framework for building autonomous AI systems that can work together to solve complex problems, all while maintaining the simplicity and clarity that AIScript is designed for. |
0 commit comments