{"id":929,"date":"2026-05-19T13:29:40","date_gmt":"2026-05-19T05:29:40","guid":{"rendered":"https:\/\/connectword.dpdns.org\/?p=929"},"modified":"2026-05-19T13:29:40","modified_gmt":"2026-05-19T05:29:40","slug":"how-to-build-an-advanced-agentic-ai-system-with-planning-tool-calling-memory-and-self-critique-using-openai-api","status":"publish","type":"post","link":"https:\/\/connectword.dpdns.org\/?p=929","title":{"rendered":"How to Build an Advanced Agentic AI System with Planning, Tool Calling, Memory, and Self-Critique Using OpenAI API"},"content":{"rendered":"<p>In this tutorial, we build an advanced agentic AI system using the OpenAI API and a hidden terminal prompt for the API key. We design the agent as a small pipeline of specialized roles: planner, tool-using executor, and critic, so that we can separate strategy, action, and quality control. We also integrate structured tools (calculator, mini knowledge-base search, JSON extraction, and file writing) so the agent can reliably compute, retrieve guidance, produce structured outputs, and save artifacts as deliverables.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\" no-line-numbers\"><code class=\" no-wrap language-php\">!pip -q install -U openai\n\n\nimport os, json, re, math, hashlib\nfrom dataclasses import dataclass, field\nfrom typing import Any, Dict, List\nfrom getpass import getpass\nfrom openai import OpenAI\n\n\nif not os.environ.get(\"OPENAI_API_KEY\"):\n   os.environ[\"OPENAI_API_KEY\"] = getpass(\"Enter OPENAI_API_KEY (hidden): \").strip()\n\n\nassert os.environ[\"OPENAI_API_KEY\"], \"OPENAI_API_KEY required\"\n\n\nclient = OpenAI()\nMODEL = \"gpt-5.2\"<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We install the OpenAI SDK and import only what we need to keep the notebook lightweight and reproducible in Colab. We take the API key via getpass() so it stays hidden and never appears in the notebook output or code. We then create an OpenAI client and set the model string once so the rest of the system can reuse it consistently.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\" no-line-numbers\"><code class=\" no-wrap language-php\">KB = [\n   {\"title\": \"Agent Protocol: Execution\", \"text\": \"Use tools only when necessary. Prefer short intermediate notes. Always verify numeric results.\"},\n   {\"title\": \"Policy: Output Quality\", \"text\": \"Final answers must include steps, checks, and deliverables. Emails must include subject and next steps.\"},\n   {\"title\": \"Playbook: Meeting Follow-up\", \"text\": \"Summarize decisions. List action items with owner and due date. Draft concise follow-up.\"},\n]\n\n\ndef _safe_calc(expr: str):\n   allowed = set(\"0123456789+-*\/().% eE\")\n   if any(ch not in allowed for ch in expr): return {\"ok\": False, \"error\": \"Invalid characters\"}\n   if re.search(r\"[A-Za-z_]\", expr): return {\"ok\": False, \"error\": \"Variables not allowed\"}\n   try:\n       val = eval(expr, {\"__builtins__\": {}}, {\"math\": math})\n       return {\"ok\": True, \"expression\": expr, \"value\": val}\n   except Exception as e:\n       return {\"ok\": False, \"error\": str(e)}\n\n\ndef _kb_search(query: str, k: int = 3):\n   q = query.lower()\n   scored = []\n   for item in KB:\n       hay = (item[\"title\"] + \" \" + item[\"text\"]).lower()\n       score = sum(1 for tok in set(re.findall(r\"w+\", q)) if tok in hay)\n       scored.append((score, item))\n   scored.sort(key=lambda x: x[0], reverse=True)\n   return {\"ok\": True, \"results\": [it for _, it in scored[:k]]}\n\n\ndef _extract_json(text: str):\n   m = re.search(r\"{.*}\", text, flags=re.DOTALL)\n   if not m: return {\"ok\": False, \"error\": \"No JSON found\"}\n   try:\n       return {\"ok\": True, \"json\": json.loads(m.group(0))}\n   except Exception as e:\n       return {\"ok\": False, \"error\": str(e), \"raw\": m.group(0)[:1500]}\n\n\ndef _write_file(path: str, content: str):\n   os.makedirs(os.path.dirname(path) or \".\", exist_ok=True)\n   with open(path, \"w\", encoding=\"utf-8\") as f: f.write(content)\n   sha = hashlib.sha256(content.encode()).hexdigest()[:16]\n   return {\"ok\": True, \"path\": path, \"sha16\": sha, \"bytes\": len(content.encode(\"utf-8\"))}<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We define a small internal \u201cknowledge base\u201d to simulate playbooks or team documentation that the agent can consult via a tool call. We implement tools that return structured dictionaries to keep tool outputs machine-readable and robust. We include a safe calculator, a keyword-based KB search, a JSON extractor for structured parsing, and a file writer to save final deliverables as artifacts.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\" no-line-numbers\"><code class=\" no-wrap language-php\">TOOLS = {\n   \"calc\": lambda expression: _safe_calc(expression),\n   \"kb_search\": lambda query, k=3: _kb_search(query, int(k)),\n   \"extract_json\": lambda text: _extract_json(text),\n   \"write_file\": lambda path, content: _write_file(path, content),\n}\n\n\nTOOL_SCHEMAS = [\n   {\"type\": \"function\",\"function\":{\"name\":\"calc\",\"description\":\"Safely compute a numeric expression.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"expression\":{\"type\":\"string\"}},\"required\":[\"expression\"]}}},\n   {\"type\": \"function\",\"function\":{\"name\":\"kb_search\",\"description\":\"Search internal mini knowledge base.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"query\":{\"type\":\"string\"},\"k\":{\"type\":\"integer\",\"default\":3}},\"required\":[\"query\"]}}},\n   {\"type\": \"function\",\"function\":{\"name\":\"extract_json\",\"description\":\"Extract and parse first JSON object from text.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"}},\"required\":[\"text\"]}}},\n   {\"type\": \"function\",\"function\":{\"name\":\"write_file\",\"description\":\"Write content to a file path.\",\"parameters\":{\"type\":\"object\",\"properties\":{\"path\":{\"type\":\"string\"},\"content\":{\"type\":\"string\"}},\"required\":[\"path\",\"content\"]}}},\n]\n\n\n@dataclass\nclass AgentState:\n   goal: str\n   memory: List[str] = field(default_factory=list)\n   trace: List[Dict[str, Any]] = field(default_factory=list)\n\n\ndef chat(messages, tools=None, tool_choice=\"auto\", temperature=0.2):\n   kwargs = dict(\n       model=MODEL,\n       messages=messages,\n       temperature=temperature,\n   )\n   if tools is not None:\n       kwargs[\"tools\"] = tools\n       kwargs[\"tool_choice\"] = tool_choice\n   return client.chat.completions.create(**kwargs)\n\n\ndef run_tool(name, args):\n   fn = TOOLS.get(name)\n   if not fn: return {\"ok\": False, \"error\": f\"Unknown tool: {name}\"}\n   try:\n       return fn(**args)\n   except Exception as e:\n       return {\"ok\": False, \"error\": str(e), \"args\": args}<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We register our Python tools in a mapping so we can call them by name during function-calling. We declare tool schemas so the model can call tools with correct argument structures. We define AgentState to store the goal, memory, and tool-call trace, allowing us to inspect what happened and debug the agent\u2019s behavior. We implement a safe chat() wrapper that only includes tool_choice when tools are provided, preventing the 400 error you saw.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\" no-line-numbers\"><code class=\" no-wrap language-php\">PLANNER_SYS = \"\"\"You are a senior planner.\nReturn STRICT JSON with keys:\nobjective (string), steps (array of strings), tool_checkpoints (array of strings).\"\"\"\n\n\nEXECUTOR_SYS = \"\"\"You are a tool-using executor.\nUse tools when needed. Keep intermediate notes short.\nWhen done, return:\n1) DRAFT output\n2) Verification checklist\"\"\"\n\n\nCRITIC_SYS = \"\"\"You are a critic.\nGiven goal + draft, return:\n- Issues (bullets)\n- Fixes (bullets)\n- Improved final answer (clean)\"\"\"\n\n\ndef plan(state: AgentState):\n   r = chat(\n       [{\"role\":\"system\",\"content\":PLANNER_SYS},{\"role\":\"user\",\"content\":state.goal}],\n       tools=None,\n       temperature=0.1,\n   )\n   txt = r.choices[0].message.content or \"\"\n   parsed = _extract_json(txt)\n   if not parsed.get(\"ok\"):\n       return {\"objective\": state.goal, \"steps\": [\"Proceed directly (planner JSON parse failed).\"], \"tool_checkpoints\": []}\n   return parsed[\"json\"]\n\n\ndef execute(state: AgentState, plan_obj: Dict[str, Any]):\n   msgs = [\n       {\"role\":\"system\",\"content\":EXECUTOR_SYS},\n       {\"role\":\"user\",\"content\":f\"GOAL:n{state.goal}nnPLAN:n{json.dumps(plan_obj, indent=2)}nnMEMORY:n\" + \"n\".join(f\"- {m}\" for m in state.memory[-10:])}\n   ]\n   for _ in range(12):\n       r = chat(msgs, tools=TOOL_SCHEMAS, tool_choice=\"auto\", temperature=0.2)\n       msg = r.choices[0].message\n       tool_calls = getattr(msg, \"tool_calls\", None)\n       if tool_calls:\n           msgs.append({\"role\":\"assistant\",\"content\":msg.content or \"\", \"tool_calls\": tool_calls})\n           for tc in tool_calls:\n               name = tc.function.name\n               args = json.loads(tc.function.arguments or \"{}\")\n               out = run_tool(name, args)\n               state.trace.append({\"tool\": name, \"args\": args, \"out\": out})\n               msgs.append({\"role\":\"tool\",\"tool_call_id\": tc.id, \"content\": json.dumps(out)})\n           continue\n       return msg.content or \"\"\n   return \"Executor stopped (iteration limit reached).\"<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We define three role prompts to separate the agent\u2019s responsibilities: the planner produces a structured plan, the executor performs the task and uses tools as needed, and the critic improves the final output. We implement a plan to request strict JSON, a loop to execute model calls, detect tool calls, execute them in Python, and then feed their outputs back to the model. This creates a true tool-using agent rather than a single-shot text generator.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\" no-line-numbers\"><code class=\" no-wrap language-php\">def critique(state: AgentState, draft: str):\n   r = chat(\n       [{\"role\":\"system\",\"content\":CRITIC_SYS},{\"role\":\"user\",\"content\":f\"GOAL:n{state.goal}nnDRAFT:n{draft}nnTRACE:n{json.dumps(state.trace, indent=2)[:9000]}\"}],\n       tools=None,\n       temperature=0.2,\n   )\n   return r.choices[0].message.content or draft\n\n\ndef run_agent(goal: str):\n   state = AgentState(goal=goal)\n   state.memory.append(\"Use kb_search if you need internal guidance or formatting playbooks.\")\n   plan_obj = plan(state)\n   draft = execute(state, plan_obj)\n   final = critique(state, draft)\n   return {\"plan\": plan_obj, \"draft\": draft, \"final\": final, \"trace\": state.trace}\n\n\ndemo_goal = \"\"\"\nFrom this transcript, produce:\nA) concise meeting summary\nB) action items as JSON array with fields: owner, action, due_date (or null)\nC) follow-up email (subject + body)\nD) Save output to \/content\/meeting_followup.md using write_file\n\n\nTranscript:\n- Decision: Ship v2 dashboard on March 15.\n- Risk: Data latency might spike; Priya will run load tests.\n- Amir will update the KPI definitions doc and share with finance.\n- Next check-in: Tuesday. Owner: Nikhil.\n\"\"\"\n\n\nresult = run_agent(demo_goal)\nprint(result[\"final\"])<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We implement critique to review the draft and produce a polished final response, using the Trace tool as additional evidence for debugging and accountability. We implement run_agent() to orchestrate the full loop: initialize state, plan, execute with tools, then critique and finalize. Finally, we provide a demo goal that forces a realistic deliverable: summary, structured action items JSON, a follow-up email, and saving output to a file via the write_file tool.<\/p>\n<p>In conclusion, we implemented a practical agentic architecture that cleanly separates planning, tool execution, and critique-based refinement. We connected the model to real tools with strict schemas, recorded a transparent tool trace for debugging, and produced artifacts by saving the final output to a file. With this structure, we can extend the agent to more production-grade workflows by adding tool retry policies, parallel sub-agents, richer memory (vector + symbolic), and evaluation harnesses to measure how well the agent plans, uses tools, and improves output over time.<\/p>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n<p>Check out\u00a0the\u00a0<strong><a href=\"https:\/\/github.com\/Marktechpost\/AI-Agents-Projects-Tutorials\/blob\/main\/Agentic%20AI%20Codes\/agentic_ai_planner_executor_critic_Marktechpost.ipynb\" target=\"_blank\" rel=\"noreferrer noopener\">Full Codes with Notebook here<\/a>.\u00a0<\/strong>Also,\u00a0feel free to follow us on\u00a0<strong><a href=\"https:\/\/x.com\/intent\/follow?screen_name=marktechpost\" target=\"_blank\" rel=\"noreferrer noopener\"><mark>Twitter<\/mark><\/a><\/strong>\u00a0and don\u2019t forget to join our\u00a0<strong><a href=\"https:\/\/www.reddit.com\/r\/machinelearningnews\/\" target=\"_blank\" rel=\"noreferrer noopener\">150k+ ML SubReddit<\/a><\/strong>\u00a0and Subscribe to\u00a0<strong><a href=\"https:\/\/www.aidevsignals.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">our Newsletter<\/a><\/strong>. Wait! are you on telegram?\u00a0<strong><a href=\"https:\/\/t.me\/machinelearningresearchnews\" target=\"_blank\" rel=\"noreferrer noopener\">now you can join us on telegram as well.<\/a><\/strong><\/p>\n<p>Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.?\u00a0<strong><a href=\"https:\/\/forms.gle\/MTNLpmJtsFA3VRVd9\" target=\"_blank\" rel=\"noreferrer noopener\"><mark>Connect with us<\/mark><\/a><\/strong><\/p>\n<p>The post <a href=\"https:\/\/www.marktechpost.com\/2026\/05\/18\/how-to-build-an-advanced-agentic-ai-system-with-planning-tool-calling-memory-and-self-critique-using-openai-api\/\">How to Build an Advanced Agentic AI System with Planning, Tool Calling, Memory, and Self-Critique Using OpenAI API<\/a> appeared first on <a href=\"https:\/\/www.marktechpost.com\/\">MarkTechPost<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>In this tutorial, we build an &hellip;<\/p>\n","protected":false},"author":1,"featured_media":29,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-929","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/posts\/929","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=929"}],"version-history":[{"count":0,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/posts\/929\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=\/wp\/v2\/media\/29"}],"wp:attachment":[{"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=929"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=929"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/connectword.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=929"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}