Tool Use & Agents

Open in GitHub

Tool use enhances retrieval-augmented generation (RAG) capabilities by enabling applications to both answer questions and automate tasks.

Tools provide a broader access to external systems compared to traditional RAG. This approach leverages LLMs’ inherent ability to reason and make decisions. By incorporating tools, developers can create agent-like applications that interact with external systems through both read and write operations.

In this chapter, we’ll explore how to build an agentic application by building an agent that can answer questions and automate tasks, enabled by a number of tools.

Setup

First, you will need to deploy the Command model on Azure via Azure AI Foundry. The deployment will create a serverless API with pay-as-you-go token based billing. You can find more information on how to deploy models in the Azure documentation.

In the example below, we are deploying the Command R+ (August 2024) model.

Once the model is deployed, you can access it via Cohere’s Python SDK. Let’s now install the Cohere SDK and set up our client.

To create a client, you need to provide the API key and the model’s base URL for the Azure endpoint. You can get these information from the Azure AI Foundry platform where you deployed the model.

PYTHON
1# %pip install cohere
2import cohere
3
4co = cohere.ClientV2(
5 api_key="AZURE_API_KEY_CHAT",
6 base_url="AZURE_ENDPOINT_CHAT", # example: "https://cohere-command-r-plus-08-2024-xyz.eastus.models.ai.azure.com/"
7)

Create tools

The pre-requisite, before we can run a tool use workflow, is to set up the tools. Let’s create three tools:

  • search_faqs: A tool for searching the FAQs of a company. For simplicity, we’ll not implement any retrieval logic, but we’ll simply pass a list of three predefined documents. In practice, we would set up a retrieval system as we did in Chapters 4, 5, and 6.
  • search_emails: A tool for searching the emails. Same as above, we’ll simply pass a list of predefined emails.
  • create_calendar_event: A tool for creating new calendar events. Again, for simplicity, we’ll only return mock successful event creations without actual implementation. In practice, we can connect to a calendar service API and implement all the necessary logic here.

Here, we are defining a Python function for each tool, but more broadly, the tool can be any function or service that can receive and send objects.

PYTHON
1def search_faqs(query):
2 faqs = [
3 {
4 "text": "Submitting Travel Expenses:\nSubmit your expenses through our user-friendly finance tool."
5 },
6 {
7 "text": "Side Projects Policy:\nWe encourage you to explore your passions! Just ensure there's no conflict of interest with our business."
8 },
9 {
10 "text": "Wellness Benefits:\nTo promote a healthy lifestyle, we provide gym memberships, on-site yoga classes, and health insurance."
11 },
12 ]
13 return faqs
14
15
16def search_emails(query):
17 emails = [
18 {
19 "from": "hr@co1t.com",
20 "to": "david@co1t.com",
21 "date": "2024-06-24",
22 "subject": "A Warm Welcome to Co1t, David!",
23 "text": "We are delighted to have you on board. Please find attached your first week's agenda.",
24 },
25 {
26 "from": "it@co1t.com",
27 "to": "david@co1t.com",
28 "date": "2024-06-24",
29 "subject": "Instructions for IT Setup",
30 "text": "Welcome, David! To get you started, please follow the attached guide to set up your work accounts.",
31 },
32 {
33 "from": "john@co1t.com",
34 "to": "david@co1t.com",
35 "date": "2024-06-24",
36 "subject": "First Week Check-In",
37 "text": "Hi David, let's chat briefly tomorrow to discuss your first week. Also, come join us for lunch this Thursday at noon to meet everyone!",
38 },
39 ]
40 return emails
41
42
43def create_calendar_event(date: str, time: str, duration: int):
44 # You can implement any logic here
45 return {
46 "is_success": True,
47 "message": f"Created a {duration} hour long event at {time} on {date}",
48 }
49
50
51functions_map = {
52 "search_faqs": search_faqs,
53 "search_emails": search_emails,
54 "create_calendar_event": create_calendar_event,
55}

Define tool schemas

The next step is to define the tool schemas in a format that can be accepted by the Chat endpoint. The schema must contain the following fields: name, description, and parameter_definitions.

This schema informs the LLM about what the tool does, and the LLM decides whether to use a particular tool based on it. Therefore, the more descriptive and specific the schema, the more likely the LLM will make the right tool call decisions.

PYTHON
1tools = [
2 {
3 "type": "function",
4 "function": {
5 "name": "search_faqs",
6 "description": "Given a user query, searches a company's frequently asked questions (FAQs) list and returns the most relevant matches to the query.",
7 "parameters": {
8 "type": "object",
9 "properties": {
10 "query": {
11 "type": "string",
12 "description": "The query from the user",
13 }
14 },
15 "required": ["query"],
16 },
17 },
18 },
19 {
20 "type": "function",
21 "function": {
22 "name": "search_emails",
23 "description": "Given a user query, searches a person's emails and returns the most relevant matches to the query.",
24 "parameters": {
25 "type": "object",
26 "properties": {
27 "query": {
28 "type": "string",
29 "description": "The query from the user",
30 }
31 },
32 "required": ["query"],
33 },
34 },
35 },
36 {
37 "type": "function",
38 "function": {
39 "name": "create_calendar_event",
40 "description": "Creates a new calendar event of the specified duration at the specified time and date. A new event cannot be created on the same time as an existing event.",
41 "parameters": {
42 "type": "object",
43 "properties": {
44 "date": {
45 "type": "string",
46 "description": "the date on which the event starts, formatted as mm/dd/yy",
47 },
48 "time": {
49 "type": "string",
50 "description": "the time of the event, formatted using 24h military time formatting",
51 },
52 "duration": {
53 "type": "number",
54 "description": "the number of hours the event lasts for",
55 },
56 },
57 "required": ["date", "time", "duration"],
58 },
59 },
60 },
61]

Run agent

Now, let’s set up the agent using Cohere’s tool use feature. We can think of a tool use system as consisting of four components:

  • The user
  • The application
  • The LLM
  • The tools

At its most basic, these four components interact in a workflow through four steps:

  • Step 1: Get user message. The LLM gets the user message (via the application).
  • Step 2: Generate tool calls. The LLM makes a decision on the tools to call (if any) and generates the tool calls.
  • Step 3: Get tool results. The application executes the tools and sends the tool results to the LLM.
  • Step 4: Generate response and citations. The LLM generates the response and citations and sends them back to the user.

Let’s create a function called run_assistant to implement these steps and print out the key events and messages along the way. This function also optionally accepts the chat history as an argument to keep the state in a multi-turn conversation.

PYTHON
1import json
2
3system_message = """## Task and Context
4You are an assistant who assists new employees of Co1t with their first week. You respond to their questions and assist them with their needs. Today is Monday, June 24, 2024"""
5
6
7def run_assistant(query, messages=None):
8 if messages is None:
9 messages = []
10
11 if "system" not in {m.get("role") for m in messages}:
12 messages.append({"role": "system", "content": system_message})
13
14 # Step 1: get user message
15 print(f"Question:\n{query}")
16 print("=" * 50)
17
18 messages.append({"role": "user", "content": query})
19
20 # Step 2: Generate tool calls (if any)
21 response = co.chat(
22 model="model", # Pass a dummy string
23 messages=messages,
24 tools=tools,
25 )
26
27 while response.message.tool_calls:
28
29 print("Tool plan:")
30 print(response.message.tool_plan, "\n")
31 print("Tool calls:")
32 for tc in response.message.tool_calls:
33 print(
34 f"Tool name: {tc.function.name} | Parameters: {tc.function.arguments}"
35 )
36 print("=" * 50)
37
38 messages.append(
39 {
40 "role": "assistant",
41 "tool_calls": response.message.tool_calls,
42 "tool_plan": response.message.tool_plan,
43 }
44 )
45
46 # Step 3: Get tool results
47 for idx, tc in enumerate(response.message.tool_calls):
48 tool_result = functions_map[tc.function.name](
49 **json.loads(tc.function.arguments)
50 )
51 tool_content = []
52 for data in tool_result:
53 tool_content.append(
54 {
55 "type": "document",
56 "document": {"data": json.dumps(data)},
57 }
58 )
59 # Optional: add an "id" field in the "document" object, otherwise IDs are auto-generated
60 messages.append(
61 {
62 "role": "tool",
63 "tool_call_id": tc.id,
64 "content": tool_content,
65 }
66 )
67
68 # Step 4: Generate response and citations
69 response = co.chat(
70 model="model", # Pass a dummy string
71 messages=messages,
72 tools=tools,
73 )
74
75 messages.append(
76 {
77 "role": "assistant",
78 "content": response.message.content[0].text,
79 }
80 )
81
82 # Print final response
83 print("Response:")
84 print(response.message.content[0].text)
85 print("=" * 50)
86
87 # Print citations (if any)
88 if response.message.citations:
89 print("\nCITATIONS:")
90 for citation in response.message.citations:
91 print(citation, "\n")
92
93 return messages

Let’s now run the agent. We’ll use an example of a new hire asking about IT access and the travel expense process.

Given three tools to choose from, the model is able to pick the right tools (in this case, search_faqs and search_emails) based on what the user is asking for.

Also, notice that the model first generates a plan about what it should do (“I will …”) before actually generating the tool call(s).

Additionally, the model also generates fine-grained citations in tool use mode based on the tool results it receives, the same way we saw with RAG.

PYTHON
1messages = run_assistant(
2 "Any doc on how do I submit travel expenses? Also, any emails about setting up IT access?"
3)
1Question:
2Any doc on how do I submit travel expenses? Also, any emails about setting up IT access?
3==================================================
4Tool plan:
5I will search for a document on how to submit travel expenses, and also search for emails about setting up IT access.
6
7Tool calls:
8Tool name: search_faqs | Parameters: {"query":"how to submit travel expenses"}
9Tool name: search_emails | Parameters: {"query":"setting up IT access"}
10==================================================
11Response:
12You can submit your travel expenses through the user-friendly finance tool.
13
14You should have received an email from it@co1t.com with instructions for setting up your IT access.
15==================================================
16
17CITATIONS:
18start=48 end=75 text='user-friendly finance tool.' sources=[ToolSource(type='tool', id='search_faqs_wkfggn2680c4:0', tool_output={'text': 'Submitting Travel Expenses:\nSubmit your expenses through our user-friendly finance tool.'})] type='TEXT_CONTENT'
19
20start=105 end=176 text='email from it@co1t.com with instructions for setting up your IT access.' sources=[ToolSource(type='tool', id='search_emails_8n0cvsh5xknt:1', tool_output={'date': '2024-06-24', 'from': 'it@co1t.com', 'subject': 'Instructions for IT Setup', 'text': 'Welcome, David! To get you started, please follow the attached guide to set up your work accounts.', 'to': 'david@co1t.com'})] type='TEXT_CONTENT'

Conclusion

In this tutorial, we learned about:

  • How to set up tools with parameter definitions for the Cohere chat API
  • How to define tools for building agentic applications
  • How to set up the agent
  • How to run a tool use workflow involving the user, the application, the LLM, and the tools
Built with