Function Call实战教程:图书查询助手Agent
从零开始,深入理解大语言模型Function Call的工作原理与实践应用
本文档详细讲解 book_agent_work.py 的代码实现,通过一个完整的图书查询助手Agent案例,帮助读者深入理解大语言模型Function Call的核心机制、实现原理和最佳实践。
目录
代码概述
这是一个基于大语言模型Function Call能力的图书查询助手Agent。它能够:
- 搜索图书(按书名、作者、分类)
- 获取图书详细信息
- 查询图书借阅状态
- 预约借阅图书
核心思想:让大语言模型理解用户意图,自动调用相应的工具函数,然后将结果整合后返回给用户。
导入模块
python
import os
import json
from openai import OpenAI
模块说明
os:用于读取环境变量(如API密钥)json:用于JSON数据的序列化和反序列化openai:OpenAI SDK,用于调用大语言模型API
工具函数定义
1. search_books - 搜索图书
python
def search_books(keyword: str = None, author: str = None, category: str = None):
功能说明
根据关键词、作者、分类等条件搜索图书。
参数说明
keyword:关键词(书名)author:作者姓名category:图书分类(小说、科技、历史、文学)
实现逻辑
python
# 1. 定义模拟图书数据库
books = [
{
"id": "book_001",
"title": "Python编程从入门到实践",
"author": "Eric Matthes",
"category": "科技",
"isbn": "9787115428028",
"available": True,
"total_copies": 5,
"available_copies": 3
},
# ... 更多图书
]
# 2. 筛选逻辑
filtered_books = []
for book in books:
# 关键词筛选:如果提供了keyword,检查书名是否包含该关键词
if keyword and keyword not in book["title"]:
continue
# 作者筛选:如果提供了author,检查作者是否匹配
if author and author not in book["author"]:
continue
# 分类筛选:如果提供了category,检查分类是否匹配
if category and book["category"] != category:
continue
# 通过所有筛选条件,添加到结果列表
filtered_books.append(book)
# 3. 返回JSON格式的结果
result = {
"total": len(filtered_books),
"books": filtered_books
}
return json.dumps(result, ensure_ascii=False)
关键点
ensure_ascii=False:确保中文字符正常显示,不被转义为Unicode编码- 返回格式:必须返回JSON字符串,因为Agent需要字符串格式的数据
2. get_book_detail - 获取图书详情
python
def get_book_detail(book_id: str):
功能说明
根据图书ID获取详细的图书信息,包括出版社、价格、页数、位置等。
实现逻辑
python
# 1. 定义详细的图书信息字典
books_detail = {
"book_001": {
"id": "book_001",
"title": "Python编程从入门到实践",
"author": "Eric Matthes",
"category": "科技",
"isbn": "9787115428028",
"publisher": "人民邮电出版社",
"publish_date": "2016-07-01",
"pages": 459,
"price": 89.00,
"description": "一本针对所有层次Python读者而作的Python入门书",
"available": True,
"total_copies": 5,
"available_copies": 3,
"location": "A区3层科技类书架"
},
# ... 更多图书详情
}
# 2. 检查图书是否存在
if book_id in books_detail:
# 存在:返回图书详细信息(JSON字符串)
return json.dumps(books_detail[book_id], ensure_ascii=False)
else:
# 不存在:返回错误信息(JSON字符串)
return json.dumps({"error": "图书不存在"}, ensure_ascii=False)
关键点
- 错误处理:如果图书不存在,返回包含error字段的JSON
- 数据格式:返回的JSON字符串可以被其他函数解析使用
3. check_availability - 查询借阅状态
python
def check_availability(book_id: str):
功能说明
查询指定图书是否可借,返回可借数量和位置信息。
实现逻辑
python
# 1. 先获取图书详情
book_detail = json.loads(get_book_detail(book_id))
# 2. 检查图书是否存在
if "error" in book_detail:
return json.dumps({
"error": "图书不存在",
"book_id": book_id
}, ensure_ascii=False)
# 3. 构建状态信息
result = {
"book_id": book_id,
"title": book_detail["title"],
"available": book_detail["available"],
"total_copies": book_detail["total_copies"],
"available_copies": book_detail["available_copies"],
"location": book_detail["location"],
# 根据可借数量判断状态
"status": "可借" if book_detail["available_copies"] > 0 else "已借完"
}
return json.dumps(result, ensure_ascii=False)
关键点
- 函数复用 :调用
get_book_detail获取基础信息,避免重复定义 json.loads():将JSON字符串转换为Python字典- 条件表达式:使用三元运算符简化状态判断
4. reserve_book - 预约借阅
python
def reserve_book(book_id: str, user_id: str):
功能说明
预约借阅指定图书,生成预约ID。
实现逻辑
python
# 1. 验证图书是否存在
book_detail = json.loads(get_book_detail(book_id))
if "error" in book_detail:
return json.dumps({
"error": "图书不存在",
"book_id": book_id
}, ensure_ascii=False)
# 2. 检查是否可借
if book_detail["available_copies"] <= 0:
return json.dumps({
"error": "图书已全部借出,无法预约",
"book_id": book_id,
"title": book_detail["title"]
}, ensure_ascii=False)
# 3. 生成预约ID(实际应用中应该从数据库生成唯一ID)
reservation_id = f"res_{book_id}_{user_id}"
# 4. 构建预约结果
result = {
"reservation_id": reservation_id,
"book_id": book_id,
"book_title": book_detail["title"],
"user_id": user_id,
"status": "预约成功",
"note": f"请在3天内到{book_detail['location']}办理借阅手续"
}
return json.dumps(result, ensure_ascii=False)
关键点
- 双重验证:先检查图书是否存在,再检查是否可借
- 错误处理:不同错误返回不同的错误信息
- f-string格式化:使用f-string方便地插入变量
JSON Schema定义
什么是JSON Schema?
JSON Schema是描述JSON数据结构的规范。在Function Call中,它告诉大语言模型:
- 有哪些函数可以调用
- 每个函数需要什么参数
- 参数的类型和含义
tools数组结构
python
tools = [
{
"type": "function",
"function": {
"name": "search_books", # 函数名
"description": "搜索图书,支持按书名、作者、分类筛选", # 函数描述
"parameters": { # 参数定义
"type": "object",
"properties": {
"keyword": {
"type": "string",
"description": "关键词(书名)"
},
"author": {
"type": "string",
"description": "作者姓名"
},
"category": {
"type": "string",
"description": "图书分类,如:小说、科技、历史、文学"
}
},
"required": [] # 必填参数列表(空表示都是可选的)
}
}
},
{
"type": "function",
"function": {
"name": "get_book_detail",
"description": "获取图书的详细信息,包括作者、出版社、价格、位置等",
"parameters": {
"type": "object",
"properties": {
"book_id": {
"type": "string",
"description": "图书ID,例如:book_001, book_002"
}
},
"required": ["book_id"]
}
}
}
# ... 其他函数定义
]
关键字段说明
type:固定为"function",表示这是一个函数调用name:函数名,必须与available_functions字典中的键一致description:函数描述,LLM根据这个描述决定是否调用该函数parameters:参数定义type: "object":表示参数是一个对象properties:定义对象的属性required:必填参数列表
为什么需要JSON Schema?
- 告诉LLM有哪些工具可用:LLM需要知道可以调用哪些函数
- 指导参数提取:LLM根据schema从用户输入中提取参数
- 类型验证:确保参数类型正确
Agent核心逻辑
函数映射字典
python
available_functions = {
"search_books": search_books,
"get_book_detail": get_book_detail,
"check_availability": check_availability,
"reserve_book": reserve_book
}
为什么可以这样写?
- Python函数是一等对象:函数可以作为值存储在字典中
search_books(不带括号):表示函数对象本身search_books()(带括号):表示调用函数并返回结果
这种写法的好处
python
# 传统写法(不推荐)
if function_name == "search_books":
result = search_books(**args)
elif function_name == "get_book_detail":
result = get_book_detail(**args)
# ... 更多elif
# 使用字典映射(推荐)
function_to_call = available_functions[function_name]
result = function_to_call(**args)
优势:
- 代码简洁
- 易于扩展(添加新函数只需在字典中添加一项)
- 避免大量if-elif语句
run_agent函数 - Agent主循环
python
def run_agent(user_query: str, api_key: str = None, model: str = "qwen-plus"):
函数流程
用户输入
↓
初始化对话历史(system + user消息)
↓
┌─────────────────────┐
│ Agent循环(最多5轮)│
│ │
│ 1. 调用LLM │
│ 2. 检查是否需要调用工具│
│ 3. 如果需要: │
│ - 执行工具函数 │
│ - 将结果加入历史 │
│ - 继续循环 │
│ 4. 如果不需要: │
│ - 返回最终答案 │
└─────────────────────┘
↓
返回结果给用户
详细代码解析
1. 初始化客户端
python
client = OpenAI(
api_key=api_key or os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
说明:
- 优先使用传入的
api_key参数 - 如果没有传入,则从环境变量
DASHSCOPE_API_KEY读取 base_url:使用阿里云DashScope的兼容模式API
2. 初始化对话历史
python
messages = [
{
"role": "system",
"content": """你是一位友好的图书管理员助手。你可以:
1. 帮助用户搜索图书(按书名、作者、分类)
2. 提供图书的详细信息
3. 查询图书的借阅状态
4. 帮助用户预约借阅图书
请根据用户的问题,使用合适的工具来获取信息并给出友好的回答。"""
},
{
"role": "user",
"content": user_query
}
]
说明:
- system消息:定义Agent的角色和能力,指导LLM的行为
- user消息:用户的查询内容
- messages列表:保存完整的对话历史
3. Agent循环
python
max_iterations = 5 # 最多进行5轮工具调用
iteration = 0
while iteration < max_iterations:
iteration += 1
print(f"\n--- 第 {iteration} 轮Agent思考 ---")
# 调用大模型
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools, # 传入工具定义
tool_choice="auto" # 让模型自主决定是否调用工具
)
response_message = response.choices[0].message
# 将模型响应加入对话历史
messages.append(response_message)
# 检查是否需要调用工具
tool_calls = response_message.tool_calls
if not tool_calls:
# 没有工具调用,说明模型已经给出最终答案
print("\n【Agent最终回复】")
print(response_message.content)
return response_message.content
# 执行工具调用
print(f"\n【Agent决定调用 {len(tool_calls)} 个工具】")
for tool_call in tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f"\n工具名称: {function_name}")
print(f"工具参数: {json.dumps(function_args, ensure_ascii=False)}")
# 执行对应的函数
if function_name in available_functions:
function_to_call = available_functions[function_name]
function_response = function_to_call(**function_args)
print(f"工具返回: {function_response[:200]}...")
# 将工具调用结果加入对话历史
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": function_name,
"content": function_response
})
else:
print(f"错误:未找到工具 {function_name}")
关键步骤解析
步骤1:调用LLM
python
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
tool_choice="auto"
)
参数说明:
model:使用的模型名称(如"qwen-plus")messages:对话历史tools:可用的工具定义tool_choice="auto":让模型自主决定是否调用工具
返回值:
response.choices[0].message:模型的消息对象- 可能包含
tool_calls字段(如果需要调用工具)
步骤2:检查工具调用
python
tool_calls = response_message.tool_calls
if not tool_calls:
# 没有工具调用,返回最终答案
return response_message.content
说明:
- 如果
tool_calls为空,说明模型已经给出最终答案 - 如果
tool_calls不为空,需要执行工具调用
步骤3:执行工具调用
python
for tool_call in tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
# 从字典中获取函数对象
function_to_call = available_functions[function_name]
# 调用函数(**function_args表示展开字典作为关键字参数)
function_response = function_to_call(**function_args)
# 将结果加入对话历史
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": function_name,
"content": function_response
})
关键点:
tool_call.function.name:LLM返回的函数名tool_call.function.arguments:LLM提取的参数(JSON字符串)json.loads():将JSON字符串转换为Python字典**function_args:展开字典作为关键字参数role: "tool":标识这是工具调用的结果
步骤4:继续循环
工具调用结果加入对话历史后,继续下一轮循环。LLM会看到:
- 之前的对话
- 工具调用的结果
- 根据结果生成最终答案或继续调用工具
运行示例
示例1:搜索图书
python
run_agent("我想找Python相关的书", api_key=api_key)
执行流程:
- LLM理解用户意图:搜索Python相关的书
- LLM调用
search_books(keyword="Python") - 函数返回搜索结果
- LLM整合结果,返回友好的回复
示例2:查询详情
python
run_agent("book_001这本书的详细信息是什么?", api_key=api_key)
执行流程:
- LLM识别出需要查询book_001的详情
- LLM调用
get_book_detail(book_id="book_001") - 函数返回图书详细信息
- LLM格式化输出给用户
示例3:预约借阅
python
run_agent("我想借Python相关的书,用户ID是user_123", api_key=api_key)
执行流程:
- LLM理解需要先搜索Python相关的书
- LLM调用
search_books(keyword="Python") - 获得搜索结果后,LLM可能需要:
- 询问用户选择哪本书
- 或者自动选择第一本
- 然后调用
reserve_book(book_id="book_001", user_id="user_123") - 返回预约结果
关键概念解析
1. Function Call的工作原理
用户输入:"我想找Python相关的书"
↓
LLM分析意图
↓
LLM决定调用 search_books(keyword="Python")
↓
执行函数,返回结果
↓
LLM整合结果,生成友好回复
↓
返回给用户
图示

2. 为什么需要JSON Schema?
问题:LLM如何知道有哪些函数可以调用?如何知道参数格式?
答案:通过JSON Schema告诉LLM:
- 有哪些函数
- 每个函数的用途
- 需要什么参数
- 参数的类型和含义
3. 为什么函数返回JSON字符串?
原因:
- Agent的消息格式要求字符串类型
- JSON格式便于LLM解析和理解
- 统一的数据格式便于处理
4. Agent循环的作用
为什么需要循环?
有些任务需要多步完成:
- 搜索图书 → 获得结果
- 查看详情 → 获得详细信息
- 预约借阅 → 完成预约
每步的结果需要传递给下一步,所以需要循环。
循环终止条件:
- LLM不再调用工具(
tool_calls为空) - 达到最大迭代次数(防止无限循环)
5. ensure_ascii=False的作用
python
# ensure_ascii=True(默认)
json.dumps({"title": "Python编程"}, ensure_ascii=True)
# 结果:'{"title": "Python\\u7f16\\u7a0b"}'
# ensure_ascii=False
json.dumps({"title": "Python编程"}, ensure_ascii=False)
# 结果:'{"title": "Python编程"}'
说明 :设置为False可以保持中文字符的可读性。
总结
代码结构
book_agent_work.py
├── 导入模块
├── 工具函数定义
│ ├── search_books
│ ├── get_book_detail
│ ├── check_availability
│ └── reserve_book
├── JSON Schema定义(tools)
├── 函数映射字典(available_functions)
└── Agent主函数(run_agent)
├── 初始化客户端
├── 初始化对话历史
└── Agent循环
├── 调用LLM
├── 检查工具调用
├── 执行工具
└── 返回结果
核心思想
- 工具函数:封装具体的业务逻辑
- JSON Schema:告诉LLM有哪些工具可用
- 函数映射:通过字符串名称动态调用函数
- Agent循环:让LLM自主决定调用哪些工具,完成复杂任务
扩展建议
- 添加更多工具函数:如查询借阅历史、续借等
- 连接真实数据库:替换模拟数据
- 添加用户认证:验证用户身份
- 错误处理优化:更详细的错误信息
- 日志记录:记录所有工具调用和结果
常见问题
Q1: 为什么工具函数必须返回JSON字符串?
A: 因为Agent的消息格式要求字符串类型,JSON格式便于LLM解析。
Q2: 可以调用多个工具吗?
A: 可以,LLM可以在一次响应中调用多个工具。
Q3: 如何添加新的工具函数?
A:
- 定义函数
- 在
tools数组中添加JSON Schema定义 - 在
available_functions字典中添加映射
Q4: Agent循环最多几次?
A : 默认5次,可以通过max_iterations参数调整。
Q5: 如何调试工具调用?
A : 代码中已经添加了print语句,可以看到:
- 工具名称
- 工具参数
- 工具返回结果
完整代码
python
"""
图书查询助手Agent示例
演示大语言模型的function call能力
"""
import os
import json
from openai import OpenAI
# ==================== 工具函数定义 ====================
def search_books(keyword: str = None, author: str = None, category: str = None):
"""
搜索图书
Args:
keyword: 关键词(书名)
author: 作者
category: 分类(如:小说、科技、历史、文学)
"""
# 模拟图书数据库
books = [
{
"id": "book_001",
"title": "Python编程从入门到实践",
"author": "Eric Matthes",
"category": "科技",
"isbn": "9787115428028",
"available": True,
"total_copies": 5,
"available_copies": 3
},
{
"id": "book_002",
"title": "三体",
"author": "刘慈欣",
"category": "小说",
"isbn": "9787536692930",
"available": True,
"total_copies": 10,
"available_copies": 2
},
{
"id": "book_003",
"title": "活着",
"author": "余华",
"category": "文学",
"isbn": "9787506365437",
"available": True,
"total_copies": 8,
"available_copies": 5
},
{
"id": "book_004",
"title": "人类简史",
"author": "尤瓦尔·赫拉利",
"category": "历史",
"isbn": "9787508647357",
"available": False,
"total_copies": 6,
"available_copies": 0
},
{
"id": "book_005",
"title": "机器学习实战",
"author": "Peter Harrington",
"category": "科技",
"isbn": "9787115317957",
"available": True,
"total_copies": 4,
"available_copies": 1
}
]
# 筛选逻辑
filtered_books = []
for book in books:
# 关键词筛选
if keyword and keyword not in book["title"]:
continue
# 作者筛选
if author and author not in book["author"]:
continue
# 分类筛选
if category and book["category"] != category:
continue
filtered_books.append(book)
result = {
"total": len(filtered_books),
"books": filtered_books
}
return json.dumps(result, ensure_ascii=False)
def get_book_detail(book_id: str):
"""
获取图书详细信息
Args:
book_id: 图书ID
"""
books_detail = {
"book_001": {
"id": "book_001",
"title": "Python编程从入门到实践",
"author": "Eric Matthes",
"category": "科技",
"isbn": "9787115428028",
"publisher": "人民邮电出版社",
"publish_date": "2016-07-01",
"pages": 459,
"price": 89.00,
"description": "一本针对所有层次Python读者而作的Python入门书",
"available": True,
"total_copies": 5,
"available_copies": 3,
"location": "A区3层科技类书架"
},
"book_002": {
"id": "book_002",
"title": "三体",
"author": "刘慈欣",
"category": "小说",
"isbn": "9787536692930",
"publisher": "重庆出版社",
"publish_date": "2008-01-01",
"pages": 302,
"price": 23.00,
"description": "科幻小说,雨果奖获奖作品",
"available": True,
"total_copies": 10,
"available_copies": 2,
"location": "B区2层小说类书架"
},
"book_003": {
"id": "book_003",
"title": "活着",
"author": "余华",
"category": "文学",
"isbn": "9787506365437",
"publisher": "作家出版社",
"publish_date": "2012-08-01",
"pages": 191,
"price": 20.00,
"description": "当代文学经典作品",
"available": True,
"total_copies": 8,
"available_copies": 5,
"location": "B区1层文学类书架"
},
"book_004": {
"id": "book_004",
"title": "人类简史",
"author": "尤瓦尔·赫拉利",
"category": "历史",
"isbn": "9787508647357",
"publisher": "中信出版社",
"publish_date": "2014-11-01",
"pages": 440,
"price": 68.00,
"description": "从认知革命、农业革命到科学革命,我们真的了解自己吗?",
"available": False,
"total_copies": 6,
"available_copies": 0,
"location": "C区2层历史类书架"
},
"book_005": {
"id": "book_005",
"title": "机器学习实战",
"author": "Peter Harrington",
"category": "科技",
"isbn": "9787115317957",
"publisher": "人民邮电出版社",
"publish_date": "2013-06-01",
"pages": 332,
"price": 69.00,
"description": "机器学习入门经典教材",
"available": True,
"total_copies": 4,
"available_copies": 1,
"location": "A区3层科技类书架"
}
}
if book_id in books_detail:
return json.dumps(books_detail[book_id], ensure_ascii=False)
else:
return json.dumps({"error": "图书不存在"}, ensure_ascii=False)
def check_availability(book_id: str):
"""
查询图书借阅状态
Args:
book_id: 图书ID
"""
book_detail = json.loads(get_book_detail(book_id))
if "error" in book_detail:
return json.dumps({
"error": "图书不存在",
"book_id": book_id
}, ensure_ascii=False)
result = {
"book_id": book_id,
"title": book_detail["title"],
"available": book_detail["available"],
"total_copies": book_detail["total_copies"],
"available_copies": book_detail["available_copies"],
"location": book_detail["location"],
"status": "可借" if book_detail["available_copies"] > 0 else "已借完"
}
return json.dumps(result, ensure_ascii=False)
def reserve_book(book_id: str, user_id: str):
"""
预约借阅图书
Args:
book_id: 图书ID
user_id: 用户ID
"""
# 验证图书是否存在
book_detail = json.loads(get_book_detail(book_id))
if "error" in book_detail:
return json.dumps({
"error": "图书不存在",
"book_id": book_id
}, ensure_ascii=False)
# 检查是否可借
if book_detail["available_copies"] <= 0:
return json.dumps({
"error": "图书已全部借出,无法预约",
"book_id": book_id,
"title": book_detail["title"]
}, ensure_ascii=False)
# 生成预约ID
reservation_id = f"res_{book_id}_{user_id}"
result = {
"reservation_id": reservation_id,
"book_id": book_id,
"book_title": book_detail["title"],
"user_id": user_id,
"status": "预约成功",
"note": f"请在3天内到{book_detail['location']}办理借阅手续"
}
return json.dumps(result, ensure_ascii=False)
# ==================== 工具函数的JSON Schema定义 ====================
tools = [
{
"type": "function",
"function": {
"name": "search_books",
"description": "搜索图书,支持按书名、作者、分类筛选",
"parameters": {
"type": "object",
"properties": {
"keyword": {
"type": "string",
"description": "关键词(书名)"
},
"author": {
"type": "string",
"description": "作者姓名"
},
"category": {
"type": "string",
"description": "图书分类,如:小说、科技、历史、文学"
}
},
"required": []
}
}
},
{
"type": "function",
"function": {
"name": "get_book_detail",
"description": "获取图书的详细信息,包括作者、出版社、价格、位置等",
"parameters": {
"type": "object",
"properties": {
"book_id": {
"type": "string",
"description": "图书ID,例如:book_001, book_002"
}
},
"required": ["book_id"]
}
}
},
{
"type": "function",
"function": {
"name": "check_availability",
"description": "查询图书是否可借,返回可借数量和位置信息",
"parameters": {
"type": "object",
"properties": {
"book_id": {
"type": "string",
"description": "图书ID"
}
},
"required": ["book_id"]
}
}
},
{
"type": "function",
"function": {
"name": "reserve_book",
"description": "预约借阅图书",
"parameters": {
"type": "object",
"properties": {
"book_id": {
"type": "string",
"description": "图书ID"
},
"user_id": {
"type": "string",
"description": "用户ID"
}
},
"required": ["book_id", "user_id"]
}
}
}
]
# ==================== Agent核心逻辑 ====================
available_functions = {
"search_books": search_books,
"get_book_detail": get_book_detail,
"check_availability": check_availability,
"reserve_book": reserve_book
}
def run_agent(user_query: str, api_key: str = None, model: str = "qwen-plus"):
"""
运行Agent,处理用户查询
Args:
user_query: 用户输入的问题
api_key: API密钥(如果不提供则从环境变量读取)
model: 使用的模型名称
"""
# 初始化OpenAI客户端
client = OpenAI(
api_key=api_key or os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1"
)
messages = [
{
"role": "system",
"content": """你是一位友好的图书管理员助手。你可以:
1. 帮助用户搜索图书(按书名、作者、分类)
2. 提供图书的详细信息
3. 查询图书的借阅状态
4. 帮助用户预约借阅图书
请根据用户的问题,使用合适的工具来获取信息并给出友好的回答。"""
},
{
"role": "user",
"content": user_query
}
]
print("\n" + "="*60)
print("【用户问题】")
print(user_query)
print("="*60)
# Agent循环:最多进行5轮工具调用
max_iterations = 5
iteration = 0
while iteration < max_iterations:
iteration += 1
print(f"\n--- 第 {iteration} 轮Agent思考 ---")
# 调用大模型
response = client.chat.completions.create(
model=model,
messages=messages,
tools=tools,
tool_choice="auto"
)
# print(response)
response_message = response.choices[0].message
# 将模型响应加入对话历史
messages.append(response_message)
# 检查是否需要调用工具
tool_calls = response_message.tool_calls
if not tool_calls:
# 没有工具调用,说明模型已经给出最终答案
print("\n【Agent最终回复】")
print(response_message.content)
print("="*60)
return response_message.content
# 执行工具调用
print(f"\n【Agent决定调用 {len(tool_calls)} 个工具】")
for tool_call in tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f"\n工具名称: {function_name}")
print(f"工具参数: {json.dumps(function_args, ensure_ascii=False)}")
# 执行对应的函数
if function_name in available_functions:
function_to_call = available_functions[function_name]
function_response = function_to_call(**function_args)
print(f"工具返回: {function_response[:200]}..." if len(function_response) > 200 else f"工具返回: {function_response}")
# 将工具调用结果加入对话历史
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": function_name,
"content": function_response
})
else:
print(f"错误:未找到工具 {function_name}")
print("\n【警告】达到最大迭代次数,Agent循环结束")
return "抱歉,处理您的请求时遇到了问题。"
if __name__ == "__main__":
api_key = "阿里云百炼自己配-https://bailian.console.aliyun.com/cn-beijing/?spm=5176.28342306.overview_recent.1.4181bf42ynMShm&tab=model#/api-key"
# 示例1:搜索图书
run_agent("我想找Python相关的书", api_key=api_key)
# 示例2:查看图书详情
run_agent("book_001这本书的详细信息是什么?", api_key=api_key)
# 示例3:查询借阅状态
run_agent("book_001这本书还能借吗?", api_key=api_key)
# 示例4:预约借阅
run_agent("我想借Python相关的书,用户ID是user_123", api_key=api_key)
# 自定义查询
# run_agent("你的问题", api_key=api_key)
参考资料
- 阿里云DashScope Function Calling文档 - 阿里云DashScope的Function Calling使用指南
- OpenAI Function Calling文档(中文翻译) - OpenAI官方文档(需科学上网)
JSON相关
- JSON Schema中文文档 - JSON Schema规范中文版
- 菜鸟教程 - JSON教程 - JSON基础教程
Python相关
- 菜鸟教程 - Python JSON - Python JSON模块使用教程
- Python官方文档 - json模块(中文) - Python官方中文文档