feat: solution for 'Практическое задание: AI-агент на LangChain'
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
.env
|
||||
dist/
|
||||
build/
|
||||
*.log
|
||||
@@ -0,0 +1,53 @@
|
||||
# Shopping List AI Agent
|
||||
|
||||
This project demonstrates a simple hierarchical AI agent built with LangChain that helps plan a shopping list, fetches prices for each item using a sub‑agent, and calculates the total cost.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.10+
|
||||
- A local LLM server (e.g., LM Studio) running at `http://localhost:1234/v1`.
|
||||
The server must expose an OpenAI‑compatible API.
|
||||
|
||||
## Installation
|
||||
|
||||
bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/your-username/shopping-list-agent.git
|
||||
cd shopping-list-agent
|
||||
|
||||
# Create a virtual environment (optional but recommended)
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows use `venv\\Scripts\\activate`
|
||||
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
|
||||
## Running the Agent
|
||||
|
||||
bash
|
||||
python src/main.py
|
||||
|
||||
|
||||
The script will ask the agent to plan a shopping list for the following request:
|
||||
|
||||
|
||||
Помоги составить список покупок: молоко, хлеб, яблоки. Я нахожусь в Казани.
|
||||
|
||||
|
||||
The agent will:
|
||||
|
||||
1. Parse the list of products and the city.
|
||||
2. For each product, invoke the `get_price` tool, which internally creates a sub‑agent that generates a realistic price table.
|
||||
3. Sum the prices and output the final total.
|
||||
|
||||
All intermediate tool calls and the final answer are printed to the console.
|
||||
|
||||
## Customization
|
||||
|
||||
- **Model**: Change the `model` parameter in `src/main.py` to match the model name exposed by your LM Studio instance.
|
||||
- **Temperature**: Adjust the `temperature` argument to control the randomness of the responses.
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
@@ -0,0 +1,70 @@
|
||||
import json
|
||||
from langchain_openai import ChatOpenAI
|
||||
from pydantic import SecretStr
|
||||
from langchain.tools import tool
|
||||
from langchain.agents import create_agent
|
||||
|
||||
# Configure the local LLM
|
||||
llm = ChatOpenAI(
|
||||
model="gpt-4o-mini", # Replace with your LM Studio model name
|
||||
base_url="http://localhost:1234/v1",
|
||||
api_key=SecretStr("fake"),
|
||||
temperature=0.7,
|
||||
)
|
||||
|
||||
@tool
|
||||
def get_price(product: str, city: str) -> str:
|
||||
"""Get realistic price for a product in a city. Returns a markdown table."""
|
||||
# Create a sub-agent that generates a price table
|
||||
sub_agent = create_agent(
|
||||
model=llm,
|
||||
tools=[],
|
||||
system_prompt=f"You are a price estimator. Provide a realistic price for {product} in {city}. Return a markdown table with columns: Product, Price (rub.), Store.",
|
||||
)
|
||||
# Invoke the sub-agent
|
||||
result = sub_agent.invoke(
|
||||
{
|
||||
"messages": [
|
||||
{"role": "user", "content": f"Provide price for {product} in {city}."}
|
||||
]
|
||||
}
|
||||
)
|
||||
# Extract the assistant message content
|
||||
messages = result.get("messages", [])
|
||||
for msg in messages:
|
||||
if msg.get("role") == "assistant" and msg.get("content"):
|
||||
return msg["content"]
|
||||
return "No price data available."
|
||||
|
||||
def main():
|
||||
# Main agent that uses the get_price tool
|
||||
agent = create_agent(
|
||||
model=llm,
|
||||
tools=[get_price],
|
||||
system_prompt="You are a shopping list planner. Use the get_price tool to find prices for items.",
|
||||
)
|
||||
# Sample user query
|
||||
user_query = "Помоги составить список покупок: молоко, хлеб, яблоки. Я нахожусь в Казани."
|
||||
# Invoke the agent
|
||||
result = agent.invoke(
|
||||
{
|
||||
"messages": [
|
||||
{"role": "human", "content": user_query}
|
||||
]
|
||||
}
|
||||
)
|
||||
# Print all messages, including tool calls and final answer
|
||||
for msg in result.get("messages", []):
|
||||
role = msg.get("role")
|
||||
content = msg.get("content")
|
||||
tool_calls = msg.get("tool_calls")
|
||||
if content:
|
||||
print(f"{role}: {content}")
|
||||
elif tool_calls:
|
||||
for call in tool_calls:
|
||||
print(f"{role} calls {call.get('name')} with args {call.get('arguments')}")
|
||||
else:
|
||||
print(f"{role}: (no content)")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,2 @@
|
||||
langchain==1.2.10
|
||||
langchain-openai==1.1.9
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import os
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langchain.tools import tool
|
||||
from langchain.agents import create_agent
|
||||
from pydantic import SecretStr
|
||||
|
||||
# Initialize the LLM
|
||||
llm = ChatOpenAI(
|
||||
model="gpt-4o-mini",
|
||||
base_url="http://localhost:1234/v1",
|
||||
api_key=SecretStr("fake"),
|
||||
temperature=0.7,
|
||||
)
|
||||
|
||||
@tool
|
||||
def get_price(product: str, city: str) -> str:
|
||||
"""Get price for a product in a city. Returns a markdown table with columns: Продукт, Цена (руб.), Магазин."""
|
||||
# Create a sub-agent to estimate the price
|
||||
sub_agent = create_agent(
|
||||
model=llm,
|
||||
tools=[],
|
||||
system_prompt=f"""You are a price estimator for product '{product}' in city '{city}'. Provide a realistic price based on historical data. Output a markdown table with columns: Продукт, Цена (руб.), Магазин."""
|
||||
)
|
||||
# Invoke the sub-agent
|
||||
sub_response = sub_agent.invoke({"messages": [{"role": "human", "content": ""}]})
|
||||
# Return the content of the last message
|
||||
return sub_response["messages"][-1]["content"]
|
||||
|
||||
# Main agent
|
||||
main_agent = create_agent(
|
||||
model=llm,
|
||||
tools=[get_price],
|
||||
system_prompt="Ты помощник по планированию покупок. Принимаешь список продуктов и город. Для каждого продукта вызывай инструмент get_price, затем суммируй цены и выдавай итоговую стоимость."
|
||||
)
|
||||
|
||||
def main():
|
||||
question = "Помоги составить список покупок: молоко, хлеб, яблоки. Я нахожусь в Казани."
|
||||
response = main_agent.invoke({"messages": [{"role": "human", "content": question}]})
|
||||
# Print all messages
|
||||
for msg in response["messages"]:
|
||||
role = msg.get("role", "")
|
||||
if role == "assistant":
|
||||
print(msg["content"])
|
||||
elif role == "tool":
|
||||
print(f"Tool call: {msg['name']} with args {msg.get('arguments')}")
|
||||
else:
|
||||
print(msg["content"])
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user