Skip to content

Commit 321f89c

Browse files
committed
add an agent app with LangGraph
1 parent a6ecb08 commit 321f89c

File tree

10 files changed

+146
-10
lines changed

10 files changed

+146
-10
lines changed

docs/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
- [Add message history (memory) > In-memory](https://python.langchain.com/v0.1/docs/expression_language/how_to/message_history/#in-memory)
1313
- [Tool calling agent](https://python.langchain.com/v0.1/docs/modules/agents/agent_types/tool_calling/)
1414
- [LangChain > Tools > Bing Search](https://python.langchain.com/v0.1/docs/integrations/tools/bing_search/)
15+
- [Tool Calling with LangChain](https://blog.langchain.dev/tool-calling-with-langchain/)
16+
- [langchain/cookbook/tool_call_messages.ipynb](https://github.com/langchain-ai/langchain/blob/master/cookbook/tool_call_messages.ipynb?ref=blog.langchain.dev)
1517

1618
## Backend
1719

frontend/entrypoint.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22

33
from frontend.solutions import (
4+
agent_langgraph,
45
azure_ai_vision,
56
azure_storage,
67
chat,
@@ -28,6 +29,7 @@ def start(
2829
SolutionType.DOCUMENT_INTELLIGENCE.value: document_intelligence.start,
2930
SolutionType.AZURE_STORAGE.value: azure_storage.start,
3031
SolutionType.AZURE_AI_VISION.value: azure_ai_vision.start,
32+
SolutionType.AGENT_LANGGRAPH.value: agent_langgraph.start,
3133
}
3234
return solutions[solution_name.upper()](
3335
backend_url=backend_url,
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import logging
2+
import operator
3+
from collections.abc import Sequence
4+
from os import getenv
5+
from typing import Annotated, TypedDict
6+
7+
import streamlit as st
8+
from dotenv import load_dotenv
9+
from langchain_core.messages import BaseMessage, HumanMessage, ToolMessage
10+
from langchain_core.runnables import ConfigurableField, RunnableLambda
11+
from langchain_openai import AzureChatOpenAI
12+
from langgraph.graph import END, StateGraph
13+
14+
from frontend.solutions.internals.tools.examples import add, exponentiate, get_current_weather, multiply
15+
16+
logger = logging.getLogger(__name__)
17+
load_dotenv("frontend.env")
18+
19+
tools = [
20+
multiply,
21+
exponentiate,
22+
add,
23+
get_current_weather,
24+
]
25+
llm = AzureChatOpenAI(
26+
api_key=getenv("AZURE_OPENAI_API_KEY"),
27+
api_version=getenv("AZURE_OPENAI_API_VERSION"),
28+
azure_endpoint=getenv("AZURE_OPENAI_ENDPOINT"),
29+
azure_deployment=getenv("AZURE_OPENAI_GPT_MODEL"),
30+
).bind_tools(tools)
31+
32+
llm_with_tools = llm.configurable_alternatives(
33+
ConfigurableField(id="llm"),
34+
)
35+
36+
37+
class AgentState(TypedDict):
38+
messages: Annotated[Sequence[BaseMessage], operator.add]
39+
40+
41+
def should_continue(state):
42+
return "continue" if state["messages"][-1].tool_calls else "end"
43+
44+
45+
def call_model(state, config):
46+
return {"messages": [llm_with_tools.invoke(state["messages"], config=config)]}
47+
48+
49+
def call_tools(state):
50+
def _invoke_tool(tool_call):
51+
tool = {tool.name: tool for tool in tools}[tool_call["name"]]
52+
return ToolMessage(tool.invoke(tool_call["args"]), tool_call_id=tool_call["id"])
53+
54+
tool_executor = RunnableLambda(_invoke_tool)
55+
last_message = state["messages"][-1]
56+
return {"messages": tool_executor.batch(last_message.tool_calls)}
57+
58+
59+
def create_graph():
60+
workflow = StateGraph(AgentState)
61+
workflow.add_node("agent", call_model)
62+
workflow.add_node("action", call_tools)
63+
workflow.set_entry_point("agent")
64+
workflow.add_conditional_edges(
65+
"agent",
66+
should_continue,
67+
{
68+
"continue": "action",
69+
"end": END,
70+
},
71+
)
72+
workflow.add_edge("action", "agent")
73+
return workflow.compile()
74+
75+
76+
def start(
77+
backend_url: str,
78+
log_level: int,
79+
):
80+
logger.setLevel(log_level)
81+
logger.debug(f"set log level to {log_level}")
82+
83+
st.title("ChatGPT-like clone")
84+
85+
graph = create_graph()
86+
87+
if prompt := st.chat_input("What is up?"):
88+
with st.chat_message("user"):
89+
st.markdown(prompt)
90+
91+
with st.spinner("Analyzing..."):
92+
with st.chat_message("assistant"):
93+
response = graph.invoke(
94+
{
95+
"messages": [
96+
HumanMessage(prompt),
97+
]
98+
}
99+
)
100+
st.json(response)

frontend/solutions/chat_langchain.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,6 @@ def get_session_history(session_id: str) -> BaseChatMessageHistory:
2222
return store[session_id]
2323

2424

25-
def run_bing_search(
26-
query: str,
27-
k=1,
28-
) -> str:
29-
from langchain_community.utilities import BingSearchAPIWrapper
30-
31-
return BingSearchAPIWrapper(k=k).run(query=query)
32-
33-
3425
def start(
3526
backend_url: str,
3627
log_level: int,

frontend/solutions/internals/__init__.py

Whitespace-only changes.

frontend/solutions/internals/tools/__init__.py

Whitespace-only changes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from langchain_core.tools import tool
2+
3+
4+
@tool
5+
def multiply(x: float, y: float) -> float:
6+
"""Multiply 'x' times 'y'."""
7+
return x * y
8+
9+
10+
@tool
11+
def exponentiate(x: float, y: float) -> float:
12+
"""Raise 'x' to the 'y'."""
13+
return x**y
14+
15+
16+
@tool
17+
def add(x: float, y: float) -> float:
18+
"""Add 'x' and 'y'."""
19+
return x + y
20+
21+
22+
@tool
23+
def get_current_weather(city: str) -> str:
24+
"""Get the current weather in 'city'."""
25+
return f"The weather in {city} is sunny."

frontend/solutions/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ class SolutionType(Enum):
99
DOCUMENT_INTELLIGENCE = "DOCUMENT_INTELLIGENCE"
1010
AZURE_STORAGE = "AZURE_STORAGE"
1111
AZURE_AI_VISION = "AZURE_AI_VISION"
12+
AGENT_LANGGRAPH = "AGENT_LANGGRAPH"

poetry.lock

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ langchain = "^0.2.1"
5252
langchain-openai = "^0.1.8"
5353
langchain-community = "^0.2.1"
5454
langsmith = "^0.1.67"
55+
langgraph = "^0.0.60"
5556

5657

5758
[tool.poetry.group.azure-functions.dependencies]

0 commit comments

Comments
 (0)