上回我们用 FastAPI 给大推行装了个门铃,, но он имеет только прямое соединение. Агент может автоматически определить, стоит ли проверять погоду, производить расчеты или искать данные. При регистрации инструментов, 意图解析地周手果奰奰异褱这料.
接上回,У нас уже был диалог с большой моделью Олламы через интерфейс API, но ее ответ основан на данных обучения модели, как он может получить данные в реальном времени?
Вы еще не сталкивались с такой неловкостью: AI-интерфейс, «厦门天天度度», он единственный в своем роде, температура 26°C, и это описание относительной влажности.
Это типичная проблема «空脑子».Если у вас нет большой модели, вы можете полагаться только на память.Сегодня возложим на агента две руки, пусть он сам проверяет погоду, считает цифры, ищет данные.
Использование FastAPI + Pydantic + функция вызова, создание четкой управляемой рабочей среды вручную.
🎯 Текст поможет вам решить эту задачу.
把技以“纯设计”的 Агент обновлен. 能电影电影电影干活的电视动生,и создать набор структурных инструментов для определения, выбора, исполнения и механизма отступления.
Вы получите расширяемую структуру ссылок на инструменты, а новая функция похожа на плагин.
🧭 Основное ядро
🚩 Пример случая: 一个生编天生的 У агента много проблем.
🚩 Инструменты, определяющие искусство: используйте Пидантик 给定利写”руководство”
🚩 意图解析与工作数据: LLM 吐出吥出设计手机后性做
🚩 异步正视器 + 电视降级:超时、parameter错、网络断не паникуйте
🚩 实战端点政新:从 /чат к /агент,只多几十行коды
🍳 第 第一:空脑子 Агент 的翻车 在线
上篇我们把 Ollama 接进了 FastAPI, 一个 /чат 端点走天下。
但If“你问他厦门明日什么погода,他回得有鼻子有眼,但一查全线没健壂没健子有眼
Это нормально, потому что В модели нет возможности использовать внешние инструменты, как и на кухне без ингредиентов., могу дать тебе только 画菜。
решение Вызов функции
Скажите модели: 嘿,你没优本事就制硬编了,正视全安全时间,Прямо скажите, какой инструмент настроить, я вам помогу запустить.
🔧 Вторая часть: Основной принцип: функция становится моделью меню.
Полная версия книги «Доброе утро»:
📋 菜谱(工作设计) → 用Функция описания модели Pydantic名、операция、тип параметра
🧠 大厨看单(意图解析) → LLM Прочитать сообщение пользователя,Возврат к функциям пользователя
👩🍳 电影炒菜(电影器) → 我们小说电影电影,去发动电影的天实的天氇议 Neon聽 API
→
Хорошо, давайте определим инструменты.Используйте FastAPI, используйте Pydantic BaseModel и используйте его для работы с базовыми моделями.
from pydantic import BaseModel
class WeatherParams(BaseModel):
city: str
date: str = "today"
Затем 把工作元объединение информации зарегистрировано в единый список. Здесь обратите внимание: насколько это возможно, не пытайтесь использовать все один из dict, первый параметр 多就乱套,Отладка до необходимого поля 凌晨三点才所代手机忘忠了.Ниже приведены два метода определения в качестве справочного материала для сравнения.
Кроме того Необходимо указать формат регистрации информации.В противном случае большая модель не распознает функцию вашего инструмента.
снова Убедитесь, что ваша модель поддерживает функцию функции инструмента.,这是我们的qwen3了电影是不电影工作,可成 qwen3.5
TOOLS = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市天气",
"parameters": WeatherParams.model_json_schema()
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "执行数学计算",
"parameters": {
"type": "object",
"properties": {
"expression": {"type": "string", "description": "数学表达式"}
},
"required": ["expression"]
}
}
}
]
⚡ Третья часть:实战——超 /agent 端点“长出双手”
Далее мы изменим его еще раз /чатстановиться /агент。
Основные изменения: сначала отправьте запрос пользователя в модель,但最佳要多传一个параметрические инструменты, скажи мне, что у тебя есть эти ребята, которые могут им воспользоваться.
модель 会 вернуть аналогичную {“name”:”get_weather”,”arguments”:{“city”:”Ханчжоу”}} 的 команда.
Я добавил новую функцию в main.py специально для решения этой проблемы:
async def execute_tool(tool_name: str, arguments: dict):
if tool_name == "get_weather":
# 这里接你们实际的天气 API,我暂时用模拟数据
city = arguments.get("city", "未知")
return f"{city}今天晴朗,26.8°C,适合写代码"
elif tool_name == "calculate":
expr = arguments.get("expression", "")
try:
result = eval(expr) # 仅演示,生产务必沙箱
return str(result)
except Exception:
return "计算出错,请检查表达式"
else:
return "这个工具我还没学会"
Вас могут спросить: «Как вы снова реализуете результаты инструмента с помощью модели?»
Вот деталь того, как я наступил на бесчисленные ямы:Мы должны объединить предыдущие сообщения и результаты инструмента во втором раунде запросов, сформировав полную историю диалога, но модель будет потеряна, так что вы будете говорить своими словами.
端电影写生法 выглядит примерно следующим образом:
@router.post("/agent")
async def agent_endpoint(req: ChatRequest, config: Settings = Depends(get_settings)):
# 第一轮:发给 LLM,带上 tools
first_resp = await call_llm(req.message, tools=TOOLS, config=config)
logger.debug(f"第一轮回复:\n{first_resp }")
# 如果没有 tool_calls,直接返回内容
tool_call = first_resp.get("tool_calls", [None])[0]
if not tool_call:
return ChatResponse(reply=first_resp["content"])
# ---- 第二轮:执行工具并拼接消息 ----
# 1. 把第一轮的 assistant 消息加入历史
messages = [
{"role": "system", "content": "你是一个能调用工具的助手,必要时使用工具,否则直接回答。当有工具返回结果时,请直接基于结果回答用户,不要再次调用工具,也不要忽略结果"},
{"role": "user", "content": req.message},
first_resp # assistant 消息,包含 tool_calls
]
# 2. 执行每个工具调用,并将结果作为 tool 消息追加
for tc in first_resp["tool_calls"]:
tool_name = tc["function"]["name"]
# arguments 返回的可能是字串,也可能已经解析为对象了,作个判断
raw_args = tc["function"]["arguments"]
if isinstance(raw_args, str):
arguments = json.loads(raw_args)
else:
arguments = raw_args # 已经是 dict 了,直接用
result = await execute_tool(tool_name, arguments) # 你的工具执行器
messages.append({
"role": "tool",
"tool_call_id": tc["id"], # 必须和上面对齐
"content": result # 工具返回的字符串
})
# 3. 把完整历史再发给模型,让它总结成人话,不用带 tools 了
final_resp = await call_llm(messages=messages, config=config)
logger.debug(f"第二轮回复:\n{first_resp }")
return ChatResponse(reply=final_resp["content"])
Машину легко повернуть:工作方法那一一个习加超时时间和 попробовать-кроме。
API-интерфейс API, API-интерфейс /агент Интерфейс 跟着一个卡死,前端прямо белый экран.
Позже я принудительно включил httpx 的超时,, а также добавил золотое правило ——Когда инструмент не может вызвать, он не выдает аномального вызова, но информация об ошибке возвращается в модель, когда инструмент дает результат, поэтому пусть у него будет свой собственный круг.Такие пользователи получают как минимум одно предложение «метеослужба временно недоступна», а не одно 500.
Предварительный вызов call_llm() также необходимо будет реструктурировать.
ядро: 用 httpx.AsyncClient 调 Оллама的 /api/chat 端点 (обратите внимание, что /api/chat,поддержка параметров инструмента,не раньше /api/generate). messages 和 tools,再电视内容的 message поле.
async def call_llm(
user_message: str = None, # 方便快捷调用
messages: list[dict] = None, # 传完整历史
tools: list[dict] = None,
config: Settings = None,
system_prompt: str = "你是一个能调用工具的助手,必要时使用工具,否则直接回答。"
):
if messages is None:
messages = [{"role": "system", "content": system_prompt}]
if user_message:
messages.append({"role": "user", "content": user_message})
# 也可以选择动态添加 system prompt,但要避免重复,这里简化处理
logger.debug(f"对话消息:\n{ messages }")
payload = {
"model": config.model_name,
"messages": messages,
"stream": False
}
if tools:
payload["tools"] = tools
async with httpx.AsyncClient() as client:
resp = await client.post(
f"{config.ollama_base_url}/api/chat",
json=payload,
timeout=30.0
)
resp.raise_for_status()
data = resp.json()
return data["message"] # 包含 content 和可能的 tool_calls
⚠️ Часть 4: Руководство
⭕ 工作设计 电影用Pydantic的 схема() Генерировать, например JSON, тип параметров, который можно использовать.
⭕ Оценка Executor используется только для демонстрации, в производственной среде используйте библиотеку безопасного анализа выражений или разрешен прямой 写死.
⭕ Если LLM не поддерживает 原生 инструмент_вызовы, также может быть самодостаточным системная подсказка Требуется вернуть определенный формат JSON, а затем вручную проанализировать, эффект такой же, как и стабильный.
⭕ для реализации инструментов можно использовать следующее: регистрация 改成图像式, коллекция декоративных инструментов,Это может быть небезопасно для детей.
Сегодняшнее обновление здесь.把一个会会модель в чате,становится 能动手干活的 Агентом, вроде как чувствует себя как 教学子子学海誀子学么轀学海一的
Если вы тоже находитесь на этой дороге, коснитесь кода.
если ты чувствуешь, что есть урожай,点赞、图像加电视агент