diff --git a/hitl-simple.py b/hitl-simple.py new file mode 100644 index 0000000..3efb24a --- /dev/null +++ b/hitl-simple.py @@ -0,0 +1,90 @@ +from langchain.agents import create_agent +from langchain_openai import ChatOpenAI +from pydantic import SecretStr +from langchain.tools import tool +from langgraph.checkpoint.memory import MemorySaver + +llm = ChatOpenAI( + model='openai/gpt-oss-20b', + base_url='http://10.128.61.70:1234/v1', + api_key=SecretStr('fake'), + temperature=.7, +) + +@tool +def get_weather(city: str, date: str) -> str: + """Это инструмент для получения погоды в указанном городе""" + + weather_agent = create_agent( + model=llm, + system_prompt=""" +Требуется предоставить прогнооз погоды для указанного города в виде таблицы +|Дата|Температура|Ветер|Давление| + +на указанную дату. Если данных нет сформируй реалистичный ответ, заполни все ячейки таблицы. +Сделай прогноз на основании исторических тенденций +""" + ) + + answer = weather_agent.invoke({ + "messages": [ + { + "role": "human", + "content": f"Какая погода в городе {city} на дату {date}?" + } + ] + }) + + return answer['messages'][-1].content + +memory = MemorySaver() + +agent = create_agent( + model=llm, + tools=[get_weather], + system_prompt='Ты полезный ассистент', + checkpointer=memory, + interrupt_before=['tools'] +) + +# answer = llm.invoke(input='Привет') + +def format_message(message) -> str: + """Форматирует одно сообщение для вывода (контент или вызов инструмента).""" + if message.content: + return message.content + + return f"{message.tool_calls[0]['name']}({message.tool_calls[0]['args']})" + +config = { 'configurable': { 'thread_id': 'someThread' } } + +user_input = input('\nВы: ') + +answer = agent.invoke( + { "messages": [{ "role": "human", "content": user_input }] }, + config, +) + +state = agent.get_state(config) + +tool_call = state.values['messages'][-1].tool_calls[0] +print(f'Агент хочет вызвать утилиту {tool_call['name']}({tool_call['args']})') +# if tool_call + +print('---') +print(*[format_message(m) for m in answer['messages']], sep='\n---\n') +print('---') + +answer = input('\nРазрешить? (Y/n): ') + +if answer.lower().strip() == 'y': + answer = agent.invoke( + None, + config, + ) + + print('---') + print(*[format_message(m) for m in answer['messages']], sep='\n---\n') + print('---') +else: + print('Отменено') diff --git a/hitl.py b/hitl.py new file mode 100644 index 0000000..5d2e7ff --- /dev/null +++ b/hitl.py @@ -0,0 +1,115 @@ +from langchain.agents import create_agent +from langchain_openai import ChatOpenAI +from pydantic import SecretStr +from langchain.tools import tool +from langgraph.checkpoint.memory import MemorySaver + +llm = ChatOpenAI( + model="openai/gpt-oss-20b", + base_url="http://10.128.61.70:1234/v1", + api_key=SecretStr("fake"), + temperature=0.7, +) + + +@tool +def get_weather(city: str, date: str) -> str: + """Это инструмент для получения погоды в указанном городе""" + + weather_agent = create_agent( + model=llm, + system_prompt=""" +Требуется предоставить прогнооз погоды для указанного города в виде таблицы +|Дата|Температура|Ветер|Давление| + +на указанную дату. Если данных нет сформируй реалистичный ответ, заполни все ячейки таблицы. +Сделай прогноз на основании исторических тенденций +""", + ) + + answer = weather_agent.invoke( + { + "messages": [ + { + "role": "human", + "content": f"Какая погода в городе {city} на дату {date}?", + } + ] + } + ) + + return answer["messages"][-1].content + + +memory = MemorySaver() + +agent = create_agent( + model=llm, + tools=[get_weather], + system_prompt="Ты полезный ассистент", + checkpointer=memory, + interrupt_before=['tools'] +) + + +def format_message(message) -> str: + """Форматирует одно сообщение для вывода (контент или вызов инструмента).""" + if message.content: + return message.content + + return f"{message.tool_calls[0]['name']}({message.tool_calls[0]['args']})" + + +step = 1 + + +def format_chunk_message(chunk): + """Форматирует одно сообщение для вывода (контент или вызов инструмента).""" + message, meta = chunk + global step + + if meta["langgraph_step"] != step: + step = meta["langgraph_step"] + print("\n --- --- --- \n") + + if message.content: + print(message.content, end="", flush=False) + + +# answer = llm.invoke(input='Привет') +config = {"configurable": {"thread_id": "someThread"}} + + +def ask_and_run(user_unput: str, config): + for chunk in agent.stream( + {"messages": [{"role": "human", "content": user_unput}]}, + config=config, + stream_mode=["messages", "updates"], + ): + chunk_type, chunk_data = chunk + if chunk_type == "messages": + format_chunk_message(chunk_data) + + if chunk_type == "updates": + if chunk_data.get("model", None): + print( + format_message(chunk_data["model"]["messages"][-1]), sep="\n---\n" + ) + + +while True: + user_input = input("\nВы: ") + if user_input == "exit": + break + + ask_and_run(user_input, config) + +# for chunk in stream: +# chunk_type, chunk_data = chunk + + +# print('---') +# print(*[format_message(m) for m in answer['messages']], sep='\n---\n') +# print('---') + +# print(answer.content) diff --git a/memory.py b/memory.py new file mode 100644 index 0000000..b3368d8 --- /dev/null +++ b/memory.py @@ -0,0 +1,72 @@ +from langchain.agents import create_agent +from langchain_openai import ChatOpenAI +from pydantic import SecretStr +from langchain.tools import tool +from langgraph.checkpoint.memory import MemorySaver + +llm = ChatOpenAI( + model='openai/gpt-oss-20b', + base_url='http://10.128.61.70:1234/v1', + api_key=SecretStr('fake'), + temperature=.7, +) + +@tool +def get_weather(city: str, date: str) -> str: + """Это инструмент для получения погоды в указанном городе""" + + weather_agent = create_agent( + model=llm, + system_prompt=""" +Требуется предоставить прогнооз погоды для указанного города в виде таблицы +|Дата|Температура|Ветер|Давление| + +на указанную дату. Если данных нет сформируй реалистичный ответ, заполни все ячейки таблицы. +Сделай прогноз на основании исторических тенденций +""" + ) + + answer = weather_agent.invoke({ + "messages": [ + { + "role": "human", + "content": f"Какая погода в городе {city} на дату {date}?" + } + ] + }) + + return answer['messages'][-1].content + +memory = MemorySaver() + +agent = create_agent( + model=llm, + tools=[get_weather], + system_prompt='Ты полезный ассистент', + checkpointer=memory +) + +# answer = llm.invoke(input='Привет') + +def format_message(message) -> str: + """Форматирует одно сообщение для вывода (контент или вызов инструмента).""" + if message.content: + return message.content + + return f"{message.tool_calls[0]['name']}({message.tool_calls[0]['args']})" + +config = { 'configurable': { 'thread_id': 'someThread' } } + +while True: + user_input = input('\nВы: ') + if user_input == 'exit': + break + + answer = agent.invoke( + { "messages": [{ "role": "human", "content": user_input }] }, + config + ) + + print('---') + print(*[format_message(m) for m in answer['messages']], sep='\n---\n') + print('---') \ No newline at end of file