anthropics-claude-cookbooks学习记录02
文章目录
- customer_service_agent.ipynb
- 创建具备客户端工具的客户服务agent
- Step 1: Set up the environment
- Step 2: Define the client-side tools
- Step 3: Simulate synthetic tool responses
- Step 4: Process tool calls and return results
- Step 5: Interact with the chatbot
- Step 6: Test the chatbot
- calculator_tool.ipynb
- 使用计算器工具与Claude协作
- Step 1: Set up the environment
- Step 2: Define the calculator tool
- Step 3: Interact with Claude
- Step 4: Try it out!
- how_to_make_sql_queries.ipynb
- 如何使用 Claude 进行 SQL 查询
- Setup
- Creating a Test Database
- Generating SQL Queries with Claude
- Executing the Generated SQL Query
今日学习:https://github.com/anthropics/anthropic-cookbook/tree/main/tool_use
学习如何将 LLM 与外部工具和功能集成以扩展其能力。
customer_service_agent.ipynb
https://github.com/anthropics/anthropic-cookbook/blob/main/tool_use/customer_service_agent.ipynb
创建具备客户端工具的客户服务agent
在本方案中,我们将演示如何利用Claude3 模型和客户端工具构建客户服务聊天机器人。该机器人将能够查询客户信息、获取订单详情,并代表客户取消订单。我们将定义必要的工具模块,并通过模拟合成响应来展示聊天机器人的各项功能。
Step 1: Set up the environment
首先,我们来安装必要的库并设置Claude API客户端。
import anthropic
client = anthropic.Client()
MODEL_NAME = "claude-3-opus-20240229"
Step 2: Define the client-side tools
接下来,我们将定义聊天机器人为协助客户所需的客户端工具。我们将创建三个功能工具:获取客户信息、查询订单详情和取消订单。
tools = [{"name": "get_customer_info","description": "根据客户ID检索客户信息。返回客户的姓名、邮箱和电话号码。","input_schema": {"type": "object","properties": {"customer_id": {"type": "string","description": "客户的唯一标识符"}},"required": ["customer_id"]}},{"name": "get_order_details", "description": "根据订单ID检索特定订单的详细信息。返回订单ID、产品名称、数量、价格和订单状态。","input_schema": {"type": "object", "properties": {"order_id": {"type": "string","description": "订单的唯一标识符"}},"required": ["order_id"]}},{"name": "cancel_order","description": "根据提供的订单ID取消订单。如果取消成功,返回确认信息。","input_schema": {"type": "object","properties": {"order_id": {"type": "string", "description": "需要取消的订单的唯一标识符"}},"required": ["order_id"]}}
]
Step 3: Simulate synthetic tool responses
由于我们没有真实的客户数据和订单信息,我们将为这些工具模拟合成的响应数据。在实际应用场景中,这些功能将与您真实的客户数据库和订单管理系统进行交互。
def get_customer_info(customer_id):# Simulated customer datacustomers = {"C1": {"name": "John Doe", "email": "john@example.com", "phone": "123-456-7890"},"C2": {"name": "Jane Smith", "email": "jane@example.com", "phone": "987-654-3210"}}return customers.get(customer_id, "Customer not found")def get_order_details(order_id):# Simulated order dataorders = {"O1": {"id": "O1", "product": "Widget A", "quantity": 2, "price": 19.99, "status": "Shipped"},"O2": {"id": "O2", "product": "Gadget B", "quantity": 1, "price": 49.99, "status": "Processing"}}return orders.get(order_id, "Order not found")def cancel_order(order_id):# Simulated order cancellationif order_id in ["O1", "O2"]:return Trueelse:return False
Step 4: Process tool calls and return results
我们将创建一个函数来处理Claude发起的工具调用,并返回相应的结果。
def process_tool_call(tool_name, tool_input):if tool_name == "get_customer_info":return get_customer_info(tool_input["customer_id"])elif tool_name == "get_order_details":return get_order_details(tool_input["order_id"])elif tool_name == "cancel_order":return cancel_order(tool_input["order_id"])
Step 5: Interact with the chatbot
现在,让我们创建一个与聊天机器人交互的函数。我们将发送用户消息,处理Claude发起的任何工具调用,并向用户返回最终响应。
import json
def chatbot_interaction(user_message):print(f"\n{'='*50}\n用户消息: {user_message}\n{'='*50}")messages = [{"role": "user", "content": user_message}]response = client.messages.create(model=MODEL_NAME,max_tokens=4096,tools=tools,messages=messages)print(f"\n初始响应:")print(f"停止原因: {response.stop_reason}")print(f"内容: {response.content}")while response.stop_reason == "tool_use":tool_use = next(block for block in response.content if block.type == "tool_use")tool_name = tool_use.nametool_input = tool_use.inputprint(f"\n使用的工具: {tool_name}")print(f"工具输入:")print(json.dumps(tool_input, indent=2))tool_result = process_tool_call(tool_name, tool_input)print(f"\n工具执行结果:")print(json.dumps(tool_result, indent=2))messages = [{"role": "user", "content": user_message},{"role": "assistant", "content": response.content},{"role": "user","content": [{"type": "tool_result","tool_use_id": tool_use.id,"content": str(tool_result),}],},]response = client.messages.create(model=MODEL_NAME,max_tokens=4096,tools=tools,messages=messages)print(f"\n响应:")print(f"停止原因: {response.stop_reason}")print(f"内容: {response.content}")final_response = next((block.text for block in response.content if hasattr(block, "text")),None,)print(f"\n最终回复: {final_response}")return final_response
Step 6: Test the chatbot
让我们用几个示例查询来测试我们的客户服务聊天机器人。
chatbot_interaction("Can you tell me the email address for customer C1?")
chatbot_interaction("What is the status of order O2?")
chatbot_interaction("Please cancel order O1 for me.")
==================================================
User Message: Can you tell me the email address for customer C1?
==================================================Initial Response:
Stop Reason: tool_use
Content: [ContentBlock(text='<thinking>The get_customer_info function retrieves a customer\'s name, email, and phone number given their customer ID. To call this function, I need the customer_id parameter. The user provided the customer ID "C1" in their request, so I have the necessary information to make the API call.</thinking>', type='text'), ContentBlockToolUse(id='toolu_019F9JHokMkJ1dHw5BEh28sA', input={'customer_id': 'C1'}, name='get_customer_info', type='tool_use')]Tool Used: get_customer_info
Tool Input:
{"customer_id": "C1"
}Tool Result:
{"name": "John Doe","email": "john@example.com","phone": "123-456-7890"
}Response:
Stop Reason: end_turn
Content: [ContentBlock(text='The email address for customer C1 (John Doe) is john@example.com.', type='text')]Final Response: The email address for customer C1 (John Doe) is john@example.com.==================================================
User Message: What is the status of order O2?
==================================================Initial Response:
Stop Reason: tool_use
Content: [ContentBlock(text='<thinking>\nBased on the provided functions, the most relevant one for this request is get_order_details, which takes an order_id parameter and returns details about that specific order, including the order status.\n\nThe user has provided an order ID in their request - "O2". So the required order_id parameter can be filled with this value.\n\nSince the required parameter is available, I can proceed with calling the get_order_details function to retrieve the order status for order O2.\n</thinking>', type='text'), ContentBlockToolUse(id='toolu_01K1u68uC94edXx8MVT35eR3', input={'order_id': 'O2'}, name='get_order_details', type='tool_use')]Tool Used: get_order_details
Tool Input:
{"order_id": "O2"
}Tool Result:
{"id": "O2","product": "Gadget B","quantity": 1,"price": 49.99,"status": "Processing"
}Response:
Stop Reason: end_turn
Content: [ContentBlock(text='Based on the details returned from the get_order_details function, the status of order O2 is "Processing".', type='text')]Final Response: Based on the details returned from the get_order_details function, the status of order O2 is "Processing".==================================================
User Message: Please cancel order O1 for me.
==================================================Initial Response:
Stop Reason: tool_use
Content: [ContentBlock(text='<thinking>\nThe relevant tool to cancel an order is the cancel_order function. \nThis function requires an order_id parameter.\nThe user provided the order ID "O1" in their request, so we have the necessary parameter to call the cancel_order function.\n</thinking>', type='text'), ContentBlockToolUse(id='toolu_01W3ZkP2QCrjHf5bKM6wvT2s', input={'order_id': 'O1'}, name='cancel_order', type='tool_use')]Tool Used: cancel_order
Tool Input:
{"order_id": "O1"
}Tool Result:
trueResponse:
Stop Reason: end_turn
Content: [ContentBlock(text='Based on the confirmation received, your order O1 has been successfully cancelled. Please let me know if there is anything else I can assist you with.', type='text')]Final Response: Based on the confirmation received, your order O1 has been successfully cancelled. Please let me know if there is anything else I can assist you with.
'Based on the confirmation received, your order O1 has been successfully cancelled. Please let me know if there is anything else I can assist you with.'
大功告成!我们已经成功使用Claude 3模型和客户端工具创建了一个客户服务聊天机器人。该机器人能够根据用户请求查询客户信息、获取订单详情以及取消订单。通过定义清晰的工具描述和参数架构,我们使Claude能够有效理解并利用可用工具来协助客户。
您可以根据实际需求扩展这个示例:集成真实的客户数据库和订单管理系统,并添加更多工具来处理更广泛的客户服务任务。
calculator_tool.ipynb
https://github.com/anthropics/anthropic-cookbook/blob/main/tool_use/calculator_tool.ipynb
使用计算器工具与Claude协作
在本方案中,我们将演示如何为Claude提供一个简易计算器工具,使其能够根据用户输入执行算术运算。我们将定义计算器工具的功能,并展示Claude如何通过调用该工具来解决数学问题。
Step 1: Set up the environment
from anthropic import Anthropic
client = Anthropic()
MODEL_NAME = "claude-3-opus-20240229"
Step 2: Define the calculator tool
我们将定义一个能够执行基本算术运算的简易计算器工具。该工具接收数学表达式作为输入,并返回计算结果。
需要注意的是,我们将对输出的表达式调用eval函数。这是一种不良实践,通常不应使用,但出于演示目的我们在此采用这种方法。
import re
def calculate(expression):# 从表达式中移除非数字和非运算符字符expression = re.sub(r'[^0-9+\-*/().]', '', expression)try:# 使用内置的eval()函数计算表达式result = eval(expression)return str(result)except (SyntaxError, ZeroDivisionError, NameError, TypeError, OverflowError):return "错误:无效的表达式"tools = [{"name": "calculator","description": "执行基本算术运算的简易计算器","input_schema": {"type": "object","properties": {"expression": {"type": "string","description": "需要计算的数学表达式(例如:'2 + 3 * 4')"}},"required": ["expression"]}}
]
在此示例中,定义了一个计算函数calculate,该函数接收数学表达式作为输入,使用正则表达式移除所有非数字或非运算符字符,然后通过内置的eval()函数对表达式进行求值。若求值成功,则返回字符串形式的结果;若求值过程中出现错误,则返回错误提示信息。
接着我们定义了计算器工具,其输入模式要求包含一个字符串类型的表达式参数。
Step 3: Interact with Claude
现在,让我们看看Claude如何与计算器工具交互来解决数学问题。
def process_tool_call(tool_name, tool_input):if tool_name == "calculator":return calculate(tool_input["expression"])def chat_with_claude(user_message):print(f"\n{'='*50}\nUser Message: {user_message}\n{'='*50}")message = client.messages.create(model=MODEL_NAME,max_tokens=4096,messages=[{"role": "user", "content": user_message}],tools=tools,)print(f"\nInitial Response:")print(f"Stop Reason: {message.stop_reason}")print(f"Content: {message.content}")if message.stop_reason == "tool_use":tool_use = next(block for block in message.content if block.type == "tool_use")tool_name = tool_use.nametool_input = tool_use.inputprint(f"\nTool Used: {tool_name}")print(f"Tool Input: {tool_input}")tool_result = process_tool_call(tool_name, tool_input)print(f"Tool Result: {tool_result}")response = client.messages.create(model=MODEL_NAME,max_tokens=4096,messages=[{"role": "user", "content": user_message},{"role": "assistant", "content": message.content},{"role": "user","content": [{"type": "tool_result","tool_use_id": tool_use.id,"content": tool_result,}],},],tools=tools,)else:response = messagefinal_response = next((block.text for block in response.content if hasattr(block, "text")),None,)print(response.content)print(f"\nFinal Response: {final_response}")return final_response
Step 4: Try it out!
现在Claude可以使用计算器了,让我们尝试向它提出几个数学问题示例。
chat_with_claude("What is the result of 1,984,135 * 9,343,116?")
chat_with_claude("Calculate (12851 - 593) * 301 + 76")
chat_with_claude("What is 15910385 divided by 193053?")
==================================================
User Message: What is the result of 1,984,135 * 9,343,116?
==================================================Initial Response:
Stop Reason: tool_use
Content: [ContentBlock(text='<thinking>\nThe calculator function is the relevant tool to answer this request, since it involves evaluating a mathematical expression.\n\nThe required parameter for the calculator function is:\nexpression: The mathematical expression to evaluate.\n\nThe human has directly provided the full expression to evaluate in their request: "1,984,135 * 9,343,116". This contains all the information needed for the required expression parameter.\n\nSo I have the necessary information to invoke the calculator tool.\n</thinking>', type='text'), ContentBlockToolUse(id='toolu_01V2mzqp5qkB5QucRFjJUJLD', input={'expression': '1984135 * 9343116'}, name='calculator', type='tool_use')]Tool Used: calculator
Tool Input: {'expression': '1984135 * 9343116'}
Tool Result: 18538003464660
[ContentBlock(text='Therefore, the result of 1,984,135 * 9,343,116 is 18,538,003,464,660.', type='text')]Final Response: Therefore, the result of 1,984,135 * 9,343,116 is 18,538,003,464,660.==================================================
User Message: Calculate (12851 - 593) * 301 + 76
==================================================Initial Response:
Stop Reason: tool_use
Content: [ContentBlock(text='<thinking>\nThe user has provided a mathematical expression to be evaluated: (12851 - 593) * 301 + 76\nThis can be handled by the calculator tool. Let\'s check if the required "expression" parameter is provided:\nexpression: "(12851 - 593) * 301 + 76" - This is directly provided by the user.\nSince the required parameter is present, we can proceed with calling the calculator tool.\n</thinking>', type='text'), ContentBlockToolUse(id='toolu_01Mrrfy9adBzzxvhfZwnyJAe', input={'expression': '(12851 - 593) * 301 + 76'}, name='calculator', type='tool_use')]Tool Used: calculator
Tool Input: {'expression': '(12851 - 593) * 301 + 76'}
Tool Result: 3689734
[ContentBlock(text='So the final result of evaluating the expression (12851 - 593) * 301 + 76 is 3689734.', type='text')]Final Response: So the final result of evaluating the expression (12851 - 593) * 301 + 76 is 3689734.==================================================
User Message: What is 15910385 divided by 193053?
==================================================Initial Response:
Stop Reason: tool_use
Content: [ContentBlock(text='<thinking>\nThe calculator function is the appropriate tool to answer this request, since it can perform basic arithmetic operations like division.\n\nThe calculator function requires a single parameter:\n- expression: The mathematical expression to evaluate\n\nIn this case, the user has provided the full expression to evaluate (15910385 divided by 193053). Since all the required information has been provided, we can proceed with calling the calculator function.\n</thinking>', type='text'), ContentBlockToolUse(id='toolu_01BfnN4LKp7oPRgmRzWeYdBG', input={'expression': '15910385 / 193053'}, name='calculator', type='tool_use')]Tool Used: calculator
Tool Input: {'expression': '15910385 / 193053'}
Tool Result: 82.41459599177428
[ContentBlock(text='So 15910385 divided by 193053 equals 82.41459599177428.', type='text')]Final Response: So 15910385 divided by 193053 equals 82.41459599177428.
how_to_make_sql_queries.ipynb
https://github.com/anthropics/anthropic-cookbook/blob/main/misc/how_to_make_sql_queries.ipynb
如何使用 Claude 进行 SQL 查询
在本笔记本中,我们将探索如何利用Claude根据自然语言问题生成SQL查询。我们将搭建一个测试数据库,将数据库结构提供给Claude,并演示它如何理解人类语言并将其转换为SQL查询。
Setup
# Import the required libraries
from anthropic import Anthropic
import sqlite3# Set up the Claude API client
client = Anthropic()
MODEL_NAME = "claude-3-opus-20240229"
Creating a Test Database
我们将使用 SQLite 创建测试数据库,并填充示例数据:
# 连接到测试数据库(如果不存在则创建)
conn = sqlite3.connect("test_db.db")
cursor = conn.cursor()# 创建示例表
cursor.execute("""CREATE TABLE IF NOT EXISTS employees (id INTEGER PRIMARY KEY,name TEXT,department TEXT,salary INTEGER)
""")# 插入示例数据
sample_data = [(1, "John Doe", "Sales", 50000),(2, "Jane Smith", "Engineering", 75000),(3, "Mike Johnson", "Sales", 60000),(4, "Emily Brown", "Engineering", 80000),(5, "David Lee", "Marketing", 55000)
]
cursor.executemany("INSERT INTO employees VALUES (?, ?, ?, ?)", sample_data)
conn.commit()
Generating SQL Queries with Claude
现在,我们定义一个函数,用于将自然语言问题发送给Claude并获取生成的SQL查询:
# 定义一个向Claude发送查询并获取响应的函数
def ask_claude(query, schema):prompt = f"""以下是数据库的结构:{schema}请根据该结构,输出能回答以下问题的SQL查询。只输出SQL查询语句,不要输出其他内容。问题:{query}
"""response = client.messages.create(model=MODEL_NAME,max_tokens=2048,messages=[{"role": 'user', "content": prompt}])return response.content[0].text
我们来获取数据库结构并将其格式化为字符串:
# 获取数据库结构
schema = cursor.execute("PRAGMA table_info(employees)").fetchall()
schema_str = "CREATE TABLE EMPLOYEES (\n" + "\n".join([f"{col[1]} {col[2]}" for col in schema]) + "\n)"
print(schema_str)
CREATE TABLE EMPLOYEES (
id INTEGER
name TEXT
department TEXT
salary INTEGER
)
现在,我们提供一个自然语言问题的示例,并将其发送给Claude:
# 示例自然语言问题
question = "What are the names and salaries of employees in the Engineering department?"
# 将问题发送给Claude并获取SQL查询
sql_query = ask_claude(question, schema_str)
print(sql_query)
SELECT name, salary
FROM EMPLOYEES
WHERE department = 'Engineering';
Executing the Generated SQL Query
最后,我们将在测试数据库上执行生成的SQL查询并输出结果:
# Execute the SQL query and print the results
results = cursor.execute(sql_query).fetchall()
for row in results:print(row)
('Jane Smith', 75000)
('Emily Brown', 80000)
完成操作后,别忘了关闭数据库连接:
# Close the database connection
conn.close()