Skip to content

Commit f0d319f

Browse files
committed
keep original readme for now
1 parent a073327 commit f0d319f

File tree

1 file changed

+341
-4
lines changed

1 file changed

+341
-4
lines changed

README.md

Lines changed: 341 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,341 @@
1-
# Libraries
2-
| Package | Version |
3-
|-------------------|---------|
4-
| toolbox-langchain | 0.1.0 |
1+
# GenAI Toolbox LangChain SDK
2+
3+
This SDK allows you to seamlessly integrate the functionalities of
4+
[Toolbox](https://github.com/googleapis/genai-toolbox) into your LangChain LLM
5+
applications, enabling advanced orchestration and interaction with GenAI models.
6+
7+
<!-- TOC ignore:true -->
8+
## Table of Contents
9+
<!-- TOC -->
10+
11+
- [Installation](#installation)
12+
- [Quickstart](#quickstart)
13+
- [Usage](#usage)
14+
- [Loading Tools](#loading-tools)
15+
- [Load a toolset](#load-a-toolset)
16+
- [Load a single tool](#load-a-single-tool)
17+
- [Use with LangChain](#use-with-langchain)
18+
- [Use with LangGraph](#use-with-langgraph)
19+
- [Represent Tools as Nodes](#represent-tools-as-nodes)
20+
- [Connect Tools with LLM](#connect-tools-with-llm)
21+
- [Manual usage](#manual-usage)
22+
- [Authenticating Tools](#authenticating-tools)
23+
- [Supported Authentication Mechanisms](#supported-authentication-mechanisms)
24+
- [Configure Tools](#configure-tools)
25+
- [Configure SDK](#configure-sdk)
26+
- [Add Authentication to a Tool](#add-authentication-to-a-tool)
27+
- [Add Authentication While Loading](#add-authentication-while-loading)
28+
- [Complete Example](#complete-example)
29+
- [Binding Parameter Values](#binding-parameter-values)
30+
- [Binding Parameters to a Tool](#binding-parameters-to-a-tool)
31+
- [Binding Parameters While Loading](#binding-parameters-while-loading)
32+
- [Binding Dynamic Values](#binding-dynamic-values)
33+
- [Asynchronous Usage](#asynchronous-usage)
34+
35+
<!-- /TOC -->
36+
37+
## Installation
38+
39+
```bash
40+
pip install toolbox-langchain
41+
```
42+
43+
## Quickstart
44+
45+
Here's a minimal example to get you started using
46+
[LangGraph](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent):
47+
48+
```py
49+
from toolbox_langchain import ToolboxClient
50+
from langchain_google_vertexai import ChatVertexAI
51+
from langgraph.prebuilt import create_react_agent
52+
53+
toolbox = ToolboxClient("http://127.0.0.1:5000")
54+
tools = toolbox.load_toolset()
55+
56+
model = ChatVertexAI(model="gemini-1.5-pro-002")
57+
agent = create_react_agent(model, tools)
58+
59+
prompt = "How's the weather today?"
60+
61+
for s in agent.stream({"messages": [("user", prompt)]}, stream_mode="values"):
62+
message = s["messages"][-1]
63+
if isinstance(message, tuple):
64+
print(message)
65+
else:
66+
message.pretty_print()
67+
```
68+
69+
## Usage
70+
71+
Import and initialize the toolbox client.
72+
73+
```py
74+
from toolbox_langchain import ToolboxClient
75+
76+
# Replace with your Toolbox service's URL
77+
toolbox = ToolboxClient("http://127.0.0.1:5000")
78+
```
79+
80+
## Loading Tools
81+
82+
### Load a toolset
83+
84+
A toolset is a collection of related tools. You can load all tools in a toolset
85+
or a specific one:
86+
87+
```py
88+
# Load all tools
89+
tools = toolbox.load_toolset()
90+
91+
# Load a specific toolset
92+
tools = toolbox.load_toolset("my-toolset")
93+
```
94+
95+
### Load a single tool
96+
97+
```py
98+
tool = toolbox.load_tool("my-tool")
99+
```
100+
101+
Loading individual tools gives you finer-grained control over which tools are
102+
available to your LLM agent.
103+
104+
## Use with LangChain
105+
106+
LangChain's agents can dynamically choose and execute tools based on the user
107+
input. Include tools loaded from the Toolbox SDK in the agent's toolkit:
108+
109+
```py
110+
from langchain_google_vertexai import ChatVertexAI
111+
112+
model = ChatVertexAI(model="gemini-1.5-pro-002")
113+
114+
# Initialize agent with tools
115+
agent = model.bind_tools(tools)
116+
117+
# Run the agent
118+
result = agent.invoke("Do something with the tools")
119+
```
120+
121+
## Use with LangGraph
122+
123+
Integrate the Toolbox SDK with LangGraph to use Toolbox service tools within a
124+
graph-based workflow. Follow the [official
125+
guide](https://langchain-ai.github.io/langgraph/) with minimal changes.
126+
127+
### Represent Tools as Nodes
128+
129+
Represent each tool as a LangGraph node, encapsulating the tool's execution within the node's functionality:
130+
131+
```py
132+
from toolbox_langchain import ToolboxClient
133+
from langgraph.graph import StateGraph, MessagesState
134+
from langgraph.prebuilt import ToolNode
135+
136+
# Define the function that calls the model
137+
def call_model(state: MessagesState):
138+
messages = state['messages']
139+
response = model.invoke(messages)
140+
return {"messages": [response]} # Return a list to add to existing messages
141+
142+
model = ChatVertexAI(model="gemini-1.5-pro-002")
143+
builder = StateGraph(MessagesState)
144+
tool_node = ToolNode(tools)
145+
146+
builder.add_node("agent", call_model)
147+
builder.add_node("tools", tool_node)
148+
```
149+
150+
### Connect Tools with LLM
151+
152+
Connect tool nodes with LLM nodes. The LLM decides which tool to use based on
153+
input or context. Tool output can be fed back into the LLM:
154+
155+
```py
156+
from typing import Literal
157+
from langgraph.graph import END, START
158+
from langchain_core.messages import HumanMessage
159+
160+
# Define the function that determines whether to continue or not
161+
def should_continue(state: MessagesState) -> Literal["tools", END]:
162+
messages = state['messages']
163+
last_message = messages[-1]
164+
if last_message.tool_calls:
165+
return "tools" # Route to "tools" node if LLM makes a tool call
166+
return END # Otherwise, stop
167+
168+
builder.add_edge(START, "agent")
169+
builder.add_conditional_edges("agent", should_continue)
170+
builder.add_edge("tools", 'agent')
171+
172+
graph = builder.compile()
173+
174+
graph.invoke({"messages": [HumanMessage(content="Do something with the tools")]})
175+
```
176+
177+
## Manual usage
178+
179+
Execute a tool manually using the `invoke` method:
180+
181+
```py
182+
result = tools[0].invoke({"name": "Alice", "age": 30})
183+
```
184+
185+
This is useful for testing tools or when you need precise control over tool
186+
execution outside of an agent framework.
187+
188+
## Authenticating Tools
189+
190+
> [!WARNING]
191+
> Always use HTTPS to connect your application with the Toolbox service,
192+
> especially when using tools with authentication configured. Using HTTP exposes
193+
> your application to serious security risks.
194+
195+
Some tools require user authentication to access sensitive data.
196+
197+
### Supported Authentication Mechanisms
198+
Toolbox currently supports authentication using the [OIDC
199+
protocol](https://openid.net/specs/openid-connect-core-1_0.html) with [ID
200+
tokens](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) (not
201+
access tokens) for [Google OAuth
202+
2.0](https://cloud.google.com/apigee/docs/api-platform/security/oauth/oauth-home).
203+
204+
### Configure Tools
205+
206+
Refer to [these
207+
instructions](https://googleapis.github.io/genai-toolbox/resources/tools/#authenticated-parameters) on
208+
configuring tools for authenticated parameters.
209+
210+
### Configure SDK
211+
212+
You need a method to retrieve an ID token from your authentication service:
213+
214+
```py
215+
async def get_auth_token():
216+
# ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
217+
# This example just returns a placeholder. Replace with your actual token retrieval.
218+
return "YOUR_ID_TOKEN" # Placeholder
219+
```
220+
221+
#### Add Authentication to a Tool
222+
223+
```py
224+
toolbox = ToolboxClient("http://127.0.0.1:5000")
225+
tools = toolbox.load_toolset()
226+
227+
auth_tool = tools[0].add_auth_token("my_auth", get_auth_token) # Single token
228+
229+
multi_auth_tool = tools[0].add_auth_tokens({"my_auth", get_auth_token}) # Multiple tokens
230+
231+
# OR
232+
233+
auth_tools = [tool.add_auth_token("my_auth", get_auth_token) for tool in tools]
234+
```
235+
236+
#### Add Authentication While Loading
237+
238+
```py
239+
auth_tool = toolbox.load_tool(auth_tokens={"my_auth": get_auth_token})
240+
241+
auth_tools = toolbox.load_toolset(auth_tokens={"my_auth": get_auth_token})
242+
```
243+
244+
> [!NOTE]
245+
> Adding auth tokens during loading only affect the tools loaded within
246+
> that call.
247+
248+
### Complete Example
249+
250+
```py
251+
import asyncio
252+
from toolbox_langchain import ToolboxClient
253+
254+
async def get_auth_token():
255+
# ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
256+
# This example just returns a placeholder. Replace with your actual token retrieval.
257+
return "YOUR_ID_TOKEN" # Placeholder
258+
259+
toolbox = ToolboxClient("http://127.0.0.1:5000")
260+
tool = toolbox.load_tool("my-tool")
261+
262+
auth_tool = tool.add_auth_token("my_auth", get_auth_token)
263+
result = auth_tool.invoke({"input": "some input"})
264+
print(result)
265+
```
266+
267+
## Binding Parameter Values
268+
269+
Predetermine values for tool parameters using the SDK. These values won't be
270+
modified by the LLM. This is useful for:
271+
272+
* **Protecting sensitive information:** API keys, secrets, etc.
273+
* **Enforcing consistency:** Ensuring specific values for certain parameters.
274+
* **Pre-filling known data:** Providing defaults or context.
275+
276+
### Binding Parameters to a Tool
277+
278+
```py
279+
toolbox = ToolboxClient("http://127.0.0.1:5000")
280+
tools = toolbox.load_toolset()
281+
282+
bound_tool = tool[0].bind_param("param", "value") # Single param
283+
284+
multi_bound_tool = tools[0].bind_params({"param1": "value1", "param2": "value2"}) # Multiple params
285+
286+
# OR
287+
288+
bound_tools = [tool.bind_param("param", "value") for tool in tools]
289+
```
290+
291+
### Binding Parameters While Loading
292+
293+
```py
294+
bound_tool = toolbox.load_tool(bound_params={"param": "value"})
295+
296+
bound_tools = toolbox.load_toolset(bound_params={"param": "value"})
297+
```
298+
299+
> [!NOTE]
300+
> Bound values during loading only affect the tools loaded in that call.
301+
302+
### Binding Dynamic Values
303+
304+
Use a function to bind dynamic values:
305+
306+
```py
307+
def get_dynamic_value():
308+
# Logic to determine the value
309+
return "dynamic_value"
310+
311+
dynamic_bound_tool = tool.bind_param("param", get_dynamic_value)
312+
```
313+
314+
> [!IMPORTANT]
315+
> You don't need to modify tool configurations to bind parameter values.
316+
317+
## Asynchronous Usage
318+
319+
For better performance through [cooperative
320+
multitasking](https://en.wikipedia.org/wiki/Cooperative_multitasking), you can
321+
use the asynchronous interfaces of the `ToolboxClient`.
322+
323+
> [!Note]
324+
> Asynchronous interfaces like `aload_tool` and `aload_toolset` require an
325+
> asynchronous environment. For guidance on running asynchronous Python
326+
> programs, see [asyncio
327+
> documentation](https://docs.python.org/3/library/asyncio-runner.html#running-an-asyncio-program).
328+
329+
```py
330+
import asyncio
331+
from toolbox_langchain import ToolboxClient
332+
333+
async def main():
334+
toolbox = ToolboxClient("http://127.0.0.1:5000")
335+
tool = await client.aload_tool("my-tool")
336+
tools = await client.aload_toolset()
337+
response = await tool.ainvoke()
338+
339+
if __name__ == "__main__":
340+
asyncio.run(main())
341+
```

0 commit comments

Comments
 (0)