Function Call实战:图书查询助手Agent

Function Call实战教程:图书查询助手Agent

从零开始,深入理解大语言模型Function Call的工作原理与实践应用

本文档详细讲解 book_agent_work.py 的代码实现,通过一个完整的图书查询助手Agent案例,帮助读者深入理解大语言模型Function Call的核心机制、实现原理和最佳实践。


目录

  1. 代码概述
  2. 导入模块
  3. 工具函数定义
  4. [JSON Schema定义](#JSON Schema定义)
  5. Agent核心逻辑
  6. 运行示例
  7. 关键概念解析

代码概述

这是一个基于大语言模型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?

  1. 告诉LLM有哪些工具可用:LLM需要知道可以调用哪些函数
  2. 指导参数提取:LLM根据schema从用户输入中提取参数
  3. 类型验证:确保参数类型正确

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)

执行流程

  1. LLM理解用户意图:搜索Python相关的书
  2. LLM调用search_books(keyword="Python")
  3. 函数返回搜索结果
  4. LLM整合结果,返回友好的回复

示例2:查询详情

python 复制代码
run_agent("book_001这本书的详细信息是什么?", api_key=api_key)

执行流程

  1. LLM识别出需要查询book_001的详情
  2. LLM调用get_book_detail(book_id="book_001")
  3. 函数返回图书详细信息
  4. LLM格式化输出给用户

示例3:预约借阅

python 复制代码
run_agent("我想借Python相关的书,用户ID是user_123", api_key=api_key)

执行流程

  1. LLM理解需要先搜索Python相关的书
  2. LLM调用search_books(keyword="Python")
  3. 获得搜索结果后,LLM可能需要:
    • 询问用户选择哪本书
    • 或者自动选择第一本
  4. 然后调用reserve_book(book_id="book_001", user_id="user_123")
  5. 返回预约结果

关键概念解析

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循环的作用

为什么需要循环?

有些任务需要多步完成:

  1. 搜索图书 → 获得结果
  2. 查看详情 → 获得详细信息
  3. 预约借阅 → 完成预约

每步的结果需要传递给下一步,所以需要循环。

循环终止条件

  • 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
        ├── 检查工具调用
        ├── 执行工具
        └── 返回结果

核心思想

  1. 工具函数:封装具体的业务逻辑
  2. JSON Schema:告诉LLM有哪些工具可用
  3. 函数映射:通过字符串名称动态调用函数
  4. Agent循环:让LLM自主决定调用哪些工具,完成复杂任务

扩展建议

  1. 添加更多工具函数:如查询借阅历史、续借等
  2. 连接真实数据库:替换模拟数据
  3. 添加用户认证:验证用户身份
  4. 错误处理优化:更详细的错误信息
  5. 日志记录:记录所有工具调用和结果

常见问题

Q1: 为什么工具函数必须返回JSON字符串?

A: 因为Agent的消息格式要求字符串类型,JSON格式便于LLM解析。

Q2: 可以调用多个工具吗?

A: 可以,LLM可以在一次响应中调用多个工具。

Q3: 如何添加新的工具函数?

A:

  1. 定义函数
  2. tools数组中添加JSON Schema定义
  3. 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)

参考资料

JSON相关

Python相关


相关推荐
心枢AI研习社2 小时前
数据库系列3——条件查询:把数据“筛对、排对”(WHERE/逻辑/范围/null/LIKE 一次讲透)
数据库·人工智能·oracle·aigc
jkyy20142 小时前
慢病智能管理+精准营销:健康有益赋能保健品行业价值重构
大数据·人工智能
azoo2 小时前
cv2.mean() 用于计算图像的像素值的平均值
人工智能·opencv·计算机视觉
啵啵鱼爱吃小猫咪2 小时前
机器人几何雅可比与解析雅可比
人工智能·学习·算法·机器学习·matlab·机器人
渡我白衣2 小时前
从线性到非线性——神经网络的原理、训练与可解释性探索
开发语言·javascript·人工智能·深度学习·神经网络·机器学习·数字电路
一颗小行星!2 小时前
我用AI“ vibe“出了一个小程序的记录和感想
人工智能·小程序
T_Fire_of_Square2 小时前
crewai 知识库针对信息安全应急演练的定位和使用
网络·人工智能
chatexcel2 小时前
ChatExcel实测:多模态识别自动做表 + 对话式数据分析 + 一键生成PPT
人工智能·powerpoint
老陈聊架构2 小时前
『AI视频创作』Remotion Skills 完全指南:用自然语言创作视频的革命
人工智能·音视频·skill·remotion