feat(react): add simple react operator and update related functionalities

- Add SimpleReactOp to react module
- Update reme_ai/__init__.py to include react module
- Modify contra_repeat_op.py to use memory_id instead of id
- Adjust datetime_handler.py to handle string datetime conversion
- Update default.yaml to include react flow content
- Modify get_observation_op.py and get_observation_with_time_op.py to use workspace_id from context
- Update test/http_client_test.py to test new react functionality
- Adjust messages.jsonl to reflect new analysis approach for Xiaomi Corporation
This commit is contained in:
jinli.yl 2025-08-29 11:55:17 +08:00
parent e4c688530c
commit adce394cd0
12 changed files with 86 additions and 93 deletions

File diff suppressed because one or more lines are too long

View file

@ -4,13 +4,12 @@ import requests
from dotenv import load_dotenv
load_dotenv()
base_url = "http://0.0.0.0:8001/"
workspace_id = "test_workspace1"
base_url = "http://0.0.0.0:8002/"
workspace_id = "test_workspace4"
def run_agent(query: str, dump_messages: bool = False):
response = requests.post(url=base_url + "agent", json={"query": query})
response = requests.post(url=base_url + "react", json={"query": query})
if response.status_code != 200:
print(response.text)
return []
@ -28,10 +27,10 @@ def run_agent(query: str, dump_messages: bool = False):
return messages
def run_summary(messages: list, dump_experience: bool = True):
response = requests.post(url=base_url + "summarizer", json={
def run_summary(messages: list, enable_dump_memory: bool = True):
response = requests.post(url=base_url + "summary_task_memory_simple", json={
"workspace_id": workspace_id,
"traj_list": [
"trajectories": [
{"messages": messages, "score": 1.0}
]
})
@ -41,14 +40,14 @@ def run_summary(messages: list, dump_experience: bool = True):
return
response = response.json()
experience_list = response["experience_list"]
if dump_experience:
with open("experience.jsonl", "w") as f:
f.write(json.dumps(experience_list, indent=2, ensure_ascii=False))
memory_list = response["metadata"]["memory_list"]
if enable_dump_memory:
with open("memory.jsonl", "w") as f:
f.write(json.dumps(memory_list, indent=2, ensure_ascii=False))
def run_retriever(query: str):
response = requests.post(url=base_url + "retriever", json={
def run_retrieve(query: str):
response = requests.post(url=base_url + "retrieve_task_memory_simple", json={
"workspace_id": workspace_id,
"query": query,
})
@ -58,20 +57,20 @@ def run_retriever(query: str):
return ""
response = response.json()
experience_merged: str = response["experience_merged"]
print(f"experience_merged={experience_merged}")
return experience_merged
answer: str = response["answer"]
print(f"answer={answer}")
return answer
def run_agent_with_experience(query_first: str, query_second: str, dump_experience: bool = True):
def run_agent_with_memory(query_first: str, query_second: str, enable_dump_memory: bool = True):
messages = run_agent(query=query_second)
run_summary(messages, dump_experience)
experience_merged = run_retriever(query_first)
messages = run_agent(query=f"{experience_merged}\n\nUser Question:\n{query_first}")
run_summary(messages, enable_dump_memory)
retrieved_memory = run_retrieve(query_first)
messages = run_agent(query=f"{retrieved_memory}\n\nUser Question:\n{query_first}")
return messages
def dump_experience():
def dump_memory():
response = requests.post(url=base_url + "vector_store", json={
"workspace_id": workspace_id,
"action": "dump",
@ -85,7 +84,7 @@ def dump_experience():
print(response.json())
def load_experience():
def load_memory():
response = requests.post(url=base_url + "vector_store", json={
"workspace_id": "test_workspace2",
"action": "load",
@ -104,6 +103,6 @@ if __name__ == "__main__":
query2 = "Analyze the company Tesla."
run_agent(query=query1, dump_messages=True)
run_agent_with_experience(query_first=query1, query_second=query2)
dump_experience()
load_experience()
run_agent_with_memory(query_first=query1, query_second=query2)
dump_memory()
load_memory()

View file

@ -1,3 +1,4 @@
from reme_ai import react
from reme_ai import retrieve
from reme_ai import summary
from reme_ai import vector_store

View file

@ -40,7 +40,7 @@ flow:
input_schema:
query:
type: "str"
description: "user query"
description: "current query"
required: true
summary_task_memory_simple:
@ -51,44 +51,10 @@ flow:
type: "list"
description: "A list of conversation trajectory information, including message content and score. This field does not need to be filled in, the system will complete it automatically."
required: false
record_task_memory:
flow_content: update_memory_freq_op >> update_memory_utility_op >> update_vector_store_op
description: "Update the freq & utility attributes of retrieved task memories"
input_schema:
workspace_id:
type: "str"
description: "workspace id"
required: true
memory_dicts:
type: "list"
description: "A list of retrieved task memory corresponding to the current task."
required: true
update_utility:
type: "bool"
description: "Whether to update the utility attribute of the retrieved task memory."
required: true
delete_task_memory:
flow_content: delete_memory_op >> update_vector_store_op
description: "Delete task memories when utility/freq < utility_threshold and freq >= freq_threshold"
input_schema:
workspace_id:
type: "str"
description: "workspace id"
required: true
freq_threshold:
type: "int"
description: "The retrieved frequency threshold for deleting task memory."
required: true
utility_threshold:
type: "float"
description: "The utility/freq threshold for deleting task memory."
required: true
vector_store:
flow_content: vector_store_action_op
description: "directly operate the vector store."
description: "Directly operates on the vector store with various management actions"
input_schema:
action:
type: "str"
@ -113,22 +79,11 @@ flow:
type: "list"
description: "A list of conversation messages information. This field does not need to be filled in, the system will complete it automatically."
required: false
op:
# retriever ops
rerank_memory_op:
backend: rerank_memory_op
llm: default
params:
enable_llm_rerank: true
enable_score_filter: false
top_k: 5
rewrite_memory_op:
backend: rewrite_memory_op
llm: default
params:
enable_llm_rewrite: true
# reconsolidate_personal_memory:
# flow_content: load_not_reflected_memory_op >> get_reflection_subject_op >> update_insight_op >> long_contra_repeat_op >> update_vector_store_op
# description: "Consolidate personal memories by generating topic insights, updating values, resolving conflicts, and updating vector store"
llm:
default:
@ -137,7 +92,6 @@ llm:
model_name: qwen3-30b-a3b-instruct-2507
params:
temperature: 0.6
embedding_model:
default:

View file

@ -0,0 +1 @@
from .simple_react_op import SimpleReactOp

View file

@ -0,0 +1,21 @@
from flowllm import C
from flowllm.context.flow_context import FlowContext
from flowllm.op.agent.react_op import ReactOp
@C.register_op()
class SimpleReactOp(ReactOp):
...
if __name__ == "__main__":
from reme_ai.config.config_parser import ConfigParser
C.set_default_service_config(parser=ConfigParser).init_by_service_config()
context = FlowContext(query="茅台和五粮现在股价多少?")
op = SimpleReactOp()
op(context=context)
# from reme_ai.schema import Message
# result = op.llm.chat(messages=[Message(**{"role": "user", "content": "你叫什么名字?"})])
# print("!!!", result)

View file

@ -130,7 +130,7 @@ class ContraRepeatOp(BaseLLMOp):
judgment_lower = judgment.lower()
if judgment_lower in ['矛盾', 'contradiction', '被包含', 'contained']:
indices_to_remove.add(idx)
deleted_memory_ids.append(memories[idx].id)
deleted_memory_ids.append(memories[idx].memory_id)
logger.info(f"Marking memory {idx + 1} for removal: {judgment} - {memories[idx].content[:100]}...")
except ValueError:

View file

@ -96,7 +96,8 @@ class GetObservationOp(BaseLLMOp):
# Create observation memory
observation = PersonalMemory(
workspace_id=self.context.get("workspace_id", ""),
workspace_id=self.context.workspace_id,
when_to_use=obs["keywords"],
content=obs["content"],
target=user_name,
author=self.llm.model_name,

View file

@ -105,7 +105,8 @@ class GetObservationWithTimeOp(BaseLLMOp):
# Create observation memory
observation = PersonalMemory(
workspace_id=self.context.get("workspace_id", ""),
workspace_id=self.context.workspace_id,
when_to_use=obs["keywords"],
content=obs["content"],
target=user_name,
author=getattr(self.llm, "model_name", "system"),

View file

@ -29,7 +29,11 @@ class DatetimeHandler(object):
"""
if isinstance(dt, str | int | float):
if isinstance(dt, str):
dt = float(dt)
try:
dt = float(dt)
except:
dt = datetime.datetime.strptime(dt, "%Y-%m-%d %H:%M:%S")
dt = dt.timestamp()
self._dt: datetime.datetime = datetime.datetime.fromtimestamp(dt)
elif isinstance(dt, datetime.datetime):
self._dt: datetime.datetime = dt

View file

@ -19,7 +19,6 @@ class RecallVectorStoreOp(BaseLLMOp):
workspace_id: str = self.context.workspace_id
nodes: List[VectorNode] = self.vector_store.search(query=query, workspace_id=workspace_id, top_k=top_k)
memory_list: List[BaseMemory] = []
memory_content_list: List[str] = []
for node in nodes:

View file

@ -78,7 +78,13 @@ async def run2(session):
result = await response.json()
print(json.dumps(result, ensure_ascii=False))
messages = [{"role": "user", "content": "我喜欢吃西瓜🍉"}]
messages = [
{"role": "user", "content": "我喜欢吃西瓜🍉"},
{"role": "user", "content": "昨天吃了苹果,很好吃"},
{"role": "user", "content": "我不太喜欢吃西瓜"},
{"role": "user", "content": "上周我去了日本,得了肠胃炎"},
{"role": "user", "content": "这周只能在家里,喝粥"},
]
async with session.post(
f"{base_url}/summary_personal_memory",
@ -96,7 +102,7 @@ async def run2(session):
async with session.post(
f"{base_url}/retrieve_personal_memory",
json={
"query": "茅台怎么样",
"query": "你知道我喜欢吃什么",
"workspace_id": workspace_id,
},
headers={"Content-Type": "application/json"}