
smolagents 构建高质量 Agent 实战指南工作流简化、信息流优化与系统化调试方法论【免费下载链接】smolagents smolagents: a barebones library for agents that think in code.项目地址: https://gitcode.com/gh_mirrors/smo/smolagents本指南围绕 smolagents 库系统讲解如何构建一个稳定、可靠、易调试的 Agent 系统从最顶层的工作流设计原则尽可能减少 LLM 调用次数、工具与 LLM 之间的信息传递优化到additional_args传参、instructions指令注入、提示词模板定制与planning_interval规划机制四个层次的调试方法论。读完本文你将掌握一套可落地的 Agent 设计规范与排查思路能够显著降低 Agent 出错率并缩短调试周期。引言好 Agent 与坏 Agent 的差距从设计开始在 smolagents 中Agent 的核心是用代码思考think in code——LLM 通过编写 Python 代码来调用工具、处理数据并最终产出答案。正因为决策权交给了 LLM同一个任务在不同设计下的成功率可能天差地别。成功与失败的 Agent 系统之间往往并不取决于模型本身的强弱而取决于工作流设计是否足够简单、信息是否充分传递给 LLM 引擎。本指南将围绕两大主题展开设计原则如何简化工作流、优化工具到 LLM 的信息流、善用additional_args传递上下文调试方法论从更换更强模型、补充指令、定制提示词模板到引入规划步骤的四种递进手段。如果你是第一次接触 Agent 构建建议先阅读 Agent 概念介绍 与 smolagents 引导教程再回到本文实践最佳实践。一、最好的 Agent 系统往往最简单尽可能简化工作流把自主决策权交给 LLM 本身就会引入出错风险。虽然一个设计良好的 Agent 系统应当具备完善的错误日志与重试机制让 LLM 引擎有机会自我纠错但从源头降低 LLM 出错概率才是更有效的策略——而这通常意味着把工作流设计得足够简单。1.1 核心原则减少 LLM 调用次数回顾 Agent 概念介绍 中的例子一个为冲浪旅行公司回答用户咨询的机器人。每当用户询问一个新的冲浪地点时如果 Agent 需要分别调用旅行距离 API和天气 API各一次那就意味着两次独立的工具调用、两次独立的 LLM 推理循环。更优的做法是把两个 API 封装进一个统一的工具return_spot_information一次调用同时获取两类数据将拼接后的结果直接返回给用户。这样做可以同时带来三方面收益降低成本每次工具调用都伴随一次 LLM 推理开销降低延迟串行多次调用变成一次调用降低出错风险LLM 每一步推理都可能产生偏差步骤越少越安全。由此可以提炼出两条可执行的行动准则尽可能将两个工具合并为一个正如上面两个 API 合并的示例尽可能用确定性函数承载逻辑而非让 LLM 自主决策——凡是能用普通 Python 函数解决的问题就不要让 LLM 去思考。1.2 源码视角工具调用如何消耗 LLM 推理从 smolagents 源码可以印证这一点在 agents.py 中MultiStepAgent.run()会进入_run_stream()主循环每一步step都要经过LLM 生成 Thought/Code → 执行代码 → 观察输出的完整循环直至出现FinalAnswerStep才终止。也就是说工具调用次数直接决定了 LLM 推理轮数与 token 消耗量。合并工具、减少步骤本质上就是在削减整个循环的迭代次数。二、优化进入 LLM 引擎的信息流可以把 LLM 引擎想象成一个被关在密闭房间里的聪明机器人它与外界唯一的沟通方式是门缝下传递的纸条——凡是没有显式写进 prompt 的信息它一概不知。因此优化信息流的两个抓手是任务描述要极其清晰工具要向 LLM 提供充分的上下文。2.1 任务描述要极其清晰Agent 由 LLM 驱动任务描述的细微差别可能造成结果的巨大差异。因此先明确地定义任务本身再优化工具向 Agent 传递信息的质量。2.2 每个工具都应充分记录信息具体的工具设计准则在每个工具的forward方法内部用print语句记录一切可能对 LLM 引擎有用的信息尤其是工具执行失败时的详细错误信息。这些 print 输出会出现在下一轮的Observation字段中成为 LLM 判断下一步行动的依据。2.3 反面示例一个糟糕的天气工具下面是一个根据地点与日期时间获取天气数据的工具先看一个糟糕的版本import datetime from smolagents import tool def get_weather_report_at_coordinates(coordinates, date_time): # 模拟函数返回 [温度(°C), 0-1 尺度的降雨概率, 浪高(米)] 列表 return [28.0, 0.35, 0.85] def convert_location_to_coordinates(location): # 返回模拟坐标 return [3.3, -42.0] tool def get_weather_api(location: str, date_time: str) - str: Returns the weather report. Args: location: the name of the place that you want the weather for. date_time: the date and time for which you want the report. lon, lat convert_location_to_coordinates(location) date_time datetime.strptime(date_time) return str(get_weather_report_at_coordinates((lon, lat), date_time))这个版本的问题在哪里date_time没有说明必须使用的格式location没有说明如何指定地点没有任何日志机制去显式暴露失败场景如地点格式不对、date_time格式错误输出格式难以理解LLM 拿到一串数字不知道含义。诚然当工具调用失败时被记录在 memory 中的错误堆栈可以帮助 LLM逆向工程出工具的正确用法并修复错误但为什么要让 LLM 承担如此重的推理负担呢2.4 正面示例信息完备的天气工具更好的构建方式如下tool def get_weather_api(location: str, date_time: str) - str: Returns the weather report. Args: location: the name of the place that you want the weather for. Should be a place name, followed by possibly a city name, then a country, like Anchor Point, Taghazout, Morocco. date_time: the date and time for which you want the report, formatted as %m/%d/%y %H:%M:%S. lon, lat convert_location_to_coordinates(location) try: date_time datetime.strptime(date_time) except Exception as e: raise ValueError(Conversion of date_time to datetime format failed, make sure to provide a string in format %m/%d/%y %H:%M:%S. Full trace: str(e)) temperature_celsius, risk_of_rain, wave_height get_weather_report_at_coordinates((lon, lat), date_time) return fWeather report for {location}, {date_time}: Temperature will be {temperature_celsius}°C, risk of rain is {risk_of_rain*100:.0f}%, wave height is {wave_height}m.改进要点参数描述给出具体格式与示例地点写法、时间格式%m/%d/%y %H:%M:%S显式捕获并重抛格式化错误错误信息中直接包含正确的格式要求与完整堆栈返回自解释的字符串温度、降雨概率、浪高全部附带单位与语义LLM 无需猜测。2.5 工具设计自检一条朴素的问题为减轻 LLM 的负担设计工具时不妨问自己如果我是一个完全不了解情况的新手第一次用这个工具编程犯错了之后靠它自己纠正错误到底有多容易这个问题的答案越容易你的工具设计就越成功。2.6 源码视角tool装饰器如何工作上述示例中的tool装饰器由 smolagents 在 tools.py 中实现tool(tool_function)会解析函数的类型注解与 docstring通过get_json_schema生成 JSON Schema函数名、描述、输入参数、返回类型然后动态创建SimpleTool(Tool)子类把被装饰函数绑定为forward静态方法。这意味着函数的docstring 直接成为工具描述会进入系统提示词system prompt供 LLM 参考——这正是为什么参数描述写得越具体LLM 犯错越少函数签名含类型注解决定 LLM 看到的工具调用接口tool只允许出现一次若检测到重复装饰会抛出错误见 tools.py。因此你写在 docstringArgs:里的每一个细节都会原样呈现给 LLM 引擎这就是信息流优化的底层机制。三、用additional_args给 Agent 传递更多参数除了一段描述任务的字符串之外你还可以通过run()方法的additional_args参数向 Agent 传递任意类型的对象例如图片、音频链接、DataFrame 等from smolagents import CodeAgent, InferenceClientModel model_id meta-llama/Llama-3.3-70B-Instruct agent CodeAgent(tools[], modelInferenceClientModel(model_idmodel_id), add_base_toolsTrue) agent.run( Why does Mike not know many people in New York?, additional_args{mp3_sound_file_url:https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/recording.mp3} )例如你可以通过additional_args传入希望 Agent 使用的图片或字符串等任何对象。3.1 源码视角additional_args如何注入 Agent 状态在 agents.py 中run()对additional_args的处理逻辑是if additional_args: self.state.update(additional_args) self.task f You have been provided with these additional arguments, that you can access directly using the keys as variables: {str(additional_args)}.也就是说传入的每个键值对会被合并进 Agent 的执行状态state随后通过python_executor.send_variables(variablesself.state)agents.py注入 Python 执行器Agent 生成的代码可以直接以键名作为变量名访问这些对象同时任务描述中也会附加一段说明告诉 LLM 这些变量的存在。因此additional_args的键名应当起得清晰、有意义让 LLM 一眼就能理解每个变量的用途。四、如何调试你的 Agent在 Agent 工作流中一部分错误是真实的功能缺陷另一部分则是 LLM 引擎没有正确推理导致的。下面给出四个层层递进的调试手段。4.1 第一步使用更强的 LLM考虑下面这个请求CodeAgent生成汽车图片的执行轨迹 New task Make me a cool car picture ──────────────────────────────────────────────────────────────────────────────────────────────────── New step ──────────────────────────────────────────────────────────────────────────────────────────────────── Agent is executing the code below: ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── image_generator(promptA cool, futuristic sports car with LED headlights, aerodynamic design, and vibrant color, high-res, photorealistic) ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Last output from code snippet: ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── /var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/tmpx09qfsdd/652f0007-3ee9-44e2-94ac-90dae6bb89a4.png Step 1: - Time taken: 16.35 seconds - Input tokens: 1,383 - Output tokens: 77 ──────────────────────────────────────────────────────────────────────────────────────────────────── New step ──────────────────────────────────────────────────────────────────────────────────────────────────── Agent is executing the code below: ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── final_answer(/var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/tmpx09qfsdd/652f0007-3ee9-44e2-94ac-90dae6bb89a4.png) ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Print outputs: Last output from code snippet: ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── /var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/tmpx09qfsdd/652f0007-3ee9-44e2-94ac-90dae6bb89a4.png Final answer: /var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/tmpx09qfsdd/652f0007-3ee9-44e2-94ac-90dae6bb89a4.png用户看到的不是图片而是一个文件路径。这看起来像系统 bug但实际上Agent 系统本身并没有出错只是 LLM 大脑犯了个错误——没有把图片输出保存到变量里之后又无法重新访问这张图片只能利用保存图片时记录下的路径于是把路径当作最终答案返回。因此调试 Agent 的第一步永远是换一个更强大的 LLM。像Qwen2/5-72B-Instruct这样的替代模型大概率不会犯这类错误。这也是排查顺序上成本最低、收益最直接的手段。4.2 第二步提供更多信息或具体指令如果你不想更换模型那么更精细的引导可以让较弱的模型同样胜任。请站在模型的角度自问如果我是模型要靠现有信息系统提示词 任务描述 工具描述解决这个任务我会不会犯难我需要更详细的指令吗根据指令的归属有三种注入位置针对所有任务的通用指令相当于我们通常理解的系统提示词作用在 Agent 初始化时通过instructions参数以字符串形式传入。注意instructions是追加到系统提示词末尾而不是替换它针对某个具体任务的细节全部写进任务描述中。任务可以非常长长到几十页都没关系针对某个具体工具的使用方法写入该工具的description属性即tool函数的 docstring。4.3 第三步修改提示词模板通常不推荐如果上述澄清手段仍不够你还可以直接修改 Agent 的提示词模板。以CodeAgent的默认系统提示词模板为例下文版本省略了零样本示例print(agent.prompt_templates[system_prompt])输出如下You are an expert assistant who can solve any task using code blobs. You will be given a task to solve as best you can. To do so, you have been given access to a list of tools: these tools are basically Python functions which you can call with code. To solve the task, you must plan forward to proceed in a series of steps, in a cycle of Thought, Code, and Observation sequences. At each step, in the Thought: sequence, you should first explain your reasoning towards solving the task and the tools that you want to use. Then in the Code sequence you should write the code in simple Python. The code sequence must be opened with {{code_block_opening_tag}}, and closed with {{code_block_closing_tag}}. During each intermediate step, you can use print() to save whatever important information you will then need. These print outputs will then appear in the Observation: field, which will be available as input for the next step. In the end you have to return a final answer using the final_answer tool. Here are a few examples using notional tools: --- Task: Generate an image of the oldest person in this document. Thought: I will proceed step by step and use the following tools: document_qa to find the oldest person in the document, then image_generator to generate an image according to the answer. {{code_block_opening_tag}} answer document_qa(documentdocument, questionWho is the oldest person mentioned?) print(answer) {{code_block_closing_tag}} Observation: The oldest person in the document is John Doe, a 55 year old lumberjack living in Newfoundland. Thought: I will now generate an image showcasing the oldest person. {{code_block_opening_tag}} image image_generator(A portrait of John Doe, a 55-year-old man living in Canada.) final_answer(image) {{code_block_closing_tag}} --- Task: What is the result of the following operation: 5 3 1294.678? Thought: I will use python code to compute the result of the operation and then return the final answer using the final_answer tool {{code_block_opening_tag}} result 5 3 1294.678 final_answer(result) {{code_block_closing_tag}} --- Task: Answer the question in the variable question about the image stored in the variable image. The question is in French. You have been provided with these additional arguments, that you can access using the keys as variables in your python code: {question: Quel est lanimal sur limage?, image: path/to/image.jpg} Thought: I will use the following tools: translator to translate the question into English and then image_qa to answer the question on the input image. {{code_block_opening_tag}} translated_question translator(questionquestion, src_langFrench, tgt_langEnglish) print(fThe translated question is {translated_question}.) answer image_qa(imageimage, questiontranslated_question) final_answer(fThe answer is {answer}) {{code_block_closing_tag}} --- Task: In a 1979 interview, Stanislaus Ulam discusses with Martin Sherwin about other great physicists of his time, including Oppenheimer. What does he say was the consequence of Einstein learning too much math on his creativity, in one word? Thought: I need to find and read the 1979 interview of Stanislaus Ulam with Martin Sherwin. {{code_block_opening_tag}} pages web_search(query1979 interview Stanislaus Ulam Martin Sherwin physicists Einstein) print(pages) {{code_block_closing_tag}} Observation: No result found for query 1979 interview Stanislaus Ulam Martin Sherwin physicists Einstein. Thought: The query was maybe too restrictive and did not find any results. Lets try again with a broader query. {{code_block_opening_tag}} pages web_search(query1979 interview Stanislaus Ulam) print(pages) {{code_block_closing_tag}} Observation: Found 6 pages: [Stanislaus Ulam 1979 interview](https://ahf.nuclearmuseum.org/voices/oral-histories/stanislaus-ulams-interview-1979/) [Ulam discusses Manhattan Project](https://ahf.nuclearmuseum.org/manhattan-project/ulam-manhattan-project/) (truncated) Thought: I will read the first 2 pages to know more. {{code_block_opening_tag}} for url in [https://ahf.nuclearmuseum.org/voices/oral-histories/stanislaus-ulams-interview-1979/, https://ahf.nuclearmuseum.org/manhattan-project/ulam-manhattan-project/]: whole_page visit_webpage(url) print(whole_page) print(\n *80 \n) # Print separator between pages {{code_block_closing_tag}} Observation: Manhattan Project Locations: Los Alamos, NM Stanislaus Ulam was a Polish-American mathematician. He worked on the Manhattan Project at Los Alamos and later helped design the hydrogen bomb. In this interview, he discusses his work at (truncated) Thought: I now have the final answer: from the webpages visited, Stanislaus Ulam says of Einstein: He learned too much mathematics and sort of diminished, it seems to me personally, it seems to me his purely physics creativity. Lets answer in one word. {{code_block_opening_tag}} final_answer(diminished) {{code_block_closing_tag}} --- Task: Which city has the highest population: Guangzhou or Shanghai? Thought: I need to get the populations for both cities and compare them: I will use the tool web_search to get the population of both cities. {{code_block_opening_tag}} for city in [Guangzhou, Shanghai]: print(fPopulation {city}:, web_search(f{city} population) {{code_block_closing_tag}} Observation: Population Guangzhou: [Guangzhou has a population of 15 million inhabitants as of 2021.] Population Shanghai: 26 million (2019) Thought: Now I know that Shanghai has the highest population. {{code_block_opening_tag}} final_answer(Shanghai) {{code_block_closing_tag}} --- Task: What is the current age of the pope, raised to the power 0.36? Thought: I will use the tool wikipedia_search to get the age of the pope, and confirm that with a web search. {{code_block_opening_tag}} pope_age_wiki wikipedia_search(querycurrent pope age) print(Pope age as per wikipedia:, pope_age_wiki) pope_age_search web_search(querycurrent pope age) print(Pope age as per google search:, pope_age_search) {{code_block_closing_tag}} Observation: Pope age: The pope Francis is currently 88 years old. Thought: I know that the pope is 88 years old. Lets compute the result using python code. {{code_block_opening_tag}} pope_current_age 88 ** 0.36 final_answer(pope_current_age) {{code_block_closing_tag}} Above example were using notional tools that might not exist for you. On top of performing computations in the Python code snippets that you create, you only have access to these tools, behaving like regular python functions: {{code_block_opening_tag}} {%- for tool in tools.values() %} {{ tool.to_code_prompt() }} {% endfor %} {{code_block_closing_tag}} {%- if managed_agents and managed_agents.values() | list %} You can also give tasks to team members. Calling a team member works similarly to calling a tool: provide the task description as the task argument. Since this team member is a real human, be as detailed and verbose as necessary in your task description. You can also include any relevant variables or context using the additional_args argument. Here is a list of the team members that you can call: {{code_block_opening_tag}} {%- for agent in managed_agents.values() %} def {{ agent.name }}(task: str, additional_args: dict[str, Any]) - str: {{ agent.description }} Args: task: Long detailed description of the task. additional_args: Dictionary of extra inputs to pass to the managed agent, e.g. images, dataframes, or any other contextual data it may need. {% endfor %} {{code_block_closing_tag}} {%- endif %} Here are the rules you should always follow to solve your task: 1. Always provide a Thought: sequence, and a {{code_block_opening_tag}} sequence ending with {{code_block_closing_tag}}, else you will fail. 2. Use only variables that you have defined! 3. Always use the right arguments for the tools. DO NOT pass the arguments as a dict as in answer wikipedia_search({query: What is the place where James Bond lives?}), but use the arguments directly as in answer wikipedia_search(queryWhat is the place where James Bond lives?). 4. For tools WITHOUT JSON output schema: Take care to not chain too many sequential tool calls in the same code block, as their output format is unpredictable. For instance, a call to wikipedia_search without a JSON output schema has an unpredictable return format, so do not have another tool call that depends on its output in the same block: rather output results with print() to use them in the next block. 5. For tools WITH JSON output schema: You can confidently chain multiple tool calls and directly access structured output fields in the same code block! When a tool has a JSON output schema, you know exactly what fields and data types to expect, allowing you to write robust code that directly accesses the structured response (e.g., result[field_name]) without needing intermediate print() statements. 6. Call a tool only when needed, and never re-do a tool call that you previously did with the exact same parameters. 7. Dont name any new variable with the same name as a tool: for instance dont name a variable final_answer. 8. Never create any notional variables in our code, as having these in your logs will derail you from the true variables. 9. You can use imports in your code, but only from the following list of modules: {{authorized_imports}} 10. The state persists between code executions: so if in one step youve created variables or imported modules, these will all persist. 11. Dont give up! Youre in charge of solving the task, not providing directions to solve it. {%- if custom_instructions %} {{custom_instructions}} {%- endif %} Now Begin!提示词模板的占位符机制如上所示模板中包含{{ tool.description }}这类 Jinja 占位符。Agent 初始化时会用工具或受管 Agentmanaged agents的自动生成描述填充它们。如果你通过system_prompt参数覆盖默认系统提示词模板新模板中可以包含以下占位符插入工具描述{%- for tool in tools.values() %} - {{ tool.to_tool_calling_prompt() }} {%- endfor %}插入受管 Agent 的描述如果有{%- if managed_agents and managed_agents.values() | list %} You can also give tasks to team members. Calling a team member works similarly to calling a tool: provide the task description as the task argument. Since this team member is a real human, be as detailed and verbose as necessary in your task description. You can also include any relevant variables or context using the additional_args argument. Here is a list of the team members that you can call: {%- for agent in managed_agents.values() %} - {{ agent.name }}: {{ agent.description }} {%- endfor %} {%- endif %}仅CodeAgent可用插入允许导入的模块列表{{authorized_imports}}运行时修改系统提示词agent.prompt_templates[system_prompt] agent.prompt_templates[system_prompt] \nHere you go!这种方式同样适用于ToolCallingAgent。但更推荐的做法是使用instructions在绝大多数场景下直接传instructions参数要简单得多agent CodeAgent(tools[], modelInferenceClientModel(model_idmodel_id), instructionsAlways talk like a 5 year old.)再次强调instructions是追加到系统提示词末尾而非替换它。源码视角提示词模板从哪来CodeAgent与ToolCallingAgent的默认提示词模板分别加载自仓库中的 YAML 文件CodeAgent对应 src/smolagents/prompts/code_agent.yaml结构化代码 Agent 另有 structured_code_agent.yamlToolCallingAgent对应 src/smolagents/prompts/toolcalling_agent.yaml。这些模板通过prompt_templates or yaml.safe_load(...)在初始化时载入见 agents.py存储在self.prompt_templates字典中agents.py。模板中的custom_instructions占位符会在每次执行时被self.instructions填充agents.py——这正是instructions参数追加而非替换系统提示词的实现依据。4.4 第四步引入额外规划步骤extra planningsmolagents 提供了一种补充性的规划步骤模型在正常动作步骤之间Agent 可以定期插入一个规划步骤。在这个步骤中不进行任何工具调用LLM 只被要求更新它已知的事实清单并基于这些事实反思接下来应当采取哪些步骤。通过planning_interval参数激活from smolagents import load_tool, CodeAgent, InferenceClientModel, WebSearchTool from dotenv import load_dotenv load_dotenv() # Import tool from Hub image_generation_tool load_tool(m-ric/text-to-image, trust_remote_codeTrue) search_tool WebSearchTool() agent CodeAgent( tools[search_tool, image_generation_tool], modelInferenceClientModel(model_idQwen/Qwen2.5-72B-Instruct), planning_interval3 # This is where you activate planning! ) # Run it! result agent.run( How long would a cheetah at full speed take to run the length of Pont Alexandre III?, )planning_interval3表示每 3 个动作步骤插入一次规划步骤。源码视角规划步骤如何被调度从 agents.py 的主循环可以看出规划步骤的调度逻辑if self.planning_interval is not None and ( self.step_number 1 or (self.step_number - 1) % self.planning_interval 0 ): ... for element in self._generate_planning_step( task, is_first_steplen(self.memory.steps) 1, stepself.step_number ): yield element即当planning_interval非空时第一步必然执行规划step_number 1此后每隔planning_interval步执行一次(step_number - 1) % planning_interval 0。_generate_planning_stepagents.py会生成一个PlanningStep记录到 memory 中其中不包含工具调用仅包含 LLM 对已知事实与后续计划的反思。这对于多步骤、长链条任务的稳定性有明显帮助。五、调试方法论总结层级手段适用场景成本1使用更强的 LLMLLM 推理错误如忘记保存变量低改一行2提供更多信息 / 具体指令任务或工具描述不充分低3修改提示词模板不推荐前两者无效且需要深度定制行为高易破坏默认能力4开启规划步骤planning_interval长链条、多步骤复杂任务中增加 token 消耗建议始终按照先换模型 → 再补信息 → 必要时定制模板 → 最后加规划的顺序排查避免一上来就动系统提示词。结合本文第二部分的信息流优化原则任务清晰、工具自解释、错误可追踪大多数 Agent 故障都能在设计阶段被提前消除。延伸阅读Agent 概念介绍理解 Thought/Code/Observation 循环smolagents 引导教程快速上手 CodeAgentAgent 参考文档MultiStepAgent 与 CodeAgent 完整参数工具参考文档tool装饰器与 Tool 类核心实现agents.pyrun 主循环、规划调度、提示词模板、tools.pytool装饰器、prompts/code_agent.yamlCodeAgent 默认提示词模板测试用例test_agents.pyAgent 行为验证【免费下载链接】smolagents smolagents: a barebones library for agents that think in code.项目地址: https://gitcode.com/gh_mirrors/smo/smolagents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考